147 |
148 |
149 |
--------------------------------------------------------------------------------
/admin/cockpit/fleet-commander-admin/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 0,
3 |
4 | "dashboard": {
5 | "fleet-commander": {
6 | "label": "Fleet Commander",
7 | "path": "index.html",
8 | "icon": "fa-paper-plane"
9 | }
10 | },
11 |
12 | "content-security-policy": "default-src 'self'; media-src 'self' blob:; img-src 'self' data:; frame-src 'self' data:;"
13 | }
14 |
--------------------------------------------------------------------------------
/admin/cockpit/fleet-commander-admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fleet-commander-admin",
3 | "version": "1.0.0",
4 | "description": "Fleet Commander",
5 | "private": true,
6 | "main": "index.js",
7 | "dependencies": {},
8 | "devDependencies": {
9 | "eslint": "^7.14.0",
10 | "eslint-config-standard": "^16.0.2",
11 | "eslint-plugin-import": "^2.22.1",
12 | "eslint-plugin-node": "^11.1.0",
13 | "eslint-plugin-promise": "^4.2.1"
14 | },
15 | "scripts": {
16 | "eslint": "eslint js/",
17 | "eslint:fix": "eslint --fix js/"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/fleet-commander/fc-admin.git"
22 | },
23 | "author": "",
24 | "license": "LGPL2.1",
25 | "bugs": {
26 | "url": "https://github.com/fleet-commander/fc-admin/issues"
27 | },
28 | "homepage": "https://fleet-commander.org/"
29 | }
30 |
--------------------------------------------------------------------------------
/admin/fleetcommander/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2014 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 | #
22 |
--------------------------------------------------------------------------------
/admin/fleetcommander/constants.py.in:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2016 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | DEFAULT_LOG_LEVEL = "@DEFAULT_LOG_LEVEL@"
23 | DEFAULT_LOG_FORMAT = "@DEFAULT_LOG_FORMAT@"
24 | DEFAULT_DEBUG_LOGGER = @DEFAULT_DEBUG_LOGGER@
25 | DEFAULT_DEBUG_PROTOCOL = @DEFAULT_DEBUG_PROTOCOL@
26 | DEFAULT_CONFIG_FILE = "@FCCONFIGFILE@"
27 |
28 | DEFAULT_DATA_DIR = "@FCADMINDIR@"
29 |
30 | DEFAULT_TMP_SESSION_DESTROY_TIMEOUT = @DEFAULT_TMP_SESSION_DESTROY_TIMEOUT@
31 | DEFAULT_AUTO_QUIT_TIMEOUT = @DEFAULT_AUTO_QUIT_TIMEOUT@
32 |
33 | DEFAULT_PROFILE_PRIORITY = @DEFAULT_PROFILE_PRIORITY@
34 |
--------------------------------------------------------------------------------
/admin/fleetcommander/goa.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2015 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | from __future__ import absolute_import
23 | from configparser import RawConfigParser, ParsingError
24 | import logging
25 |
26 | logger = logging.getLogger(__name__)
27 |
28 |
29 | class GOAProvidersLoader:
30 | """
31 | GOA providers reader
32 | """
33 |
34 | def __init__(self, providers_file):
35 | """
36 | Class initialization
37 | """
38 | self.path = providers_file
39 | self._providers = {}
40 | self._configparser = RawConfigParser()
41 | try:
42 | self._configparser.read(providers_file)
43 | except IOError as e:
44 | logger.error("Could not find GOA providers file %s", providers_file)
45 | raise e
46 | except ParsingError as e:
47 | logger.error("There was an error parsing %s", providers_file)
48 | raise e
49 | except Exception as e:
50 | logger.error("There was an unknown error parsing %s", providers_file)
51 | raise e
52 | self.read_data()
53 |
54 | def read_data(self):
55 | for section in self._configparser.sections():
56 | if section.startswith("Provider "):
57 | provider = section.split()[1]
58 | self._providers[provider] = {
59 | "name": self.generate_readable_name(provider),
60 | "services": {},
61 | }
62 | for option in self._configparser.options(section):
63 | if option == "providername":
64 | name = self._configparser.get(section, option)
65 | self._providers[provider]["name"] = name
66 | elif option.endswith("enabled"):
67 | service = option[:-7].title() + "Enabled"
68 | name = self.generate_readable_name(service[:-7])
69 | enabled = self._configparser.getboolean(section, option)
70 | # Generate readable name
71 | self._providers[provider]["services"][service] = {
72 | "name": name,
73 | "enabled": enabled,
74 | }
75 |
76 | def generate_readable_name(self, identifier):
77 | """
78 | Generates readable names for providers and services
79 | """
80 | stripped = identifier.strip()
81 | if stripped:
82 | return stripped.title().replace("_", " ")
83 | return "Enabled"
84 |
85 | def get_providers(self):
86 | return self._providers
87 |
--------------------------------------------------------------------------------
/admin/fleetcommander/mergers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2014 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 | #
22 |
23 | from __future__ import absolute_import
24 | import logging
25 |
26 | logger = logging.getLogger(__name__)
27 |
28 |
29 | class BaseChangeMerger:
30 | """
31 | Base change merger class
32 | """
33 |
34 | KEY_NAME = "key"
35 |
36 | def get_key_from_change(self, change):
37 | """
38 | Return change key identifier
39 | """
40 | if self.KEY_NAME in change:
41 | return change[self.KEY_NAME]
42 |
43 | return None
44 |
45 | def merge(self, *args):
46 | """
47 | Merge changesets in the given order
48 | """
49 | index = {}
50 | for changeset in args:
51 | for change in changeset:
52 | key = self.get_key_from_change(change)
53 | index[key] = change
54 | return list(index.values())
55 |
56 |
57 | class GSettingsChangeMerger(BaseChangeMerger):
58 | """
59 | GSettings change merger class
60 | """
61 |
62 |
63 | class LibreOfficeChangeMerger(BaseChangeMerger):
64 | """
65 | LibreOffice change merger class
66 | """
67 |
68 |
69 | class NetworkManagerChangeMerger(BaseChangeMerger):
70 | """
71 | Network manager change merger class
72 | """
73 |
74 | KEY_NAME = "uuid"
75 |
76 |
77 | class ChromiumChangeMerger(BaseChangeMerger):
78 | """
79 | Chromium/Chrome change merger class
80 | """
81 |
82 | KEY_NAME = "key"
83 |
84 | def merge(self, *args):
85 | """
86 | Merge changesets in the given order
87 | """
88 | index = {}
89 | bookmarks = []
90 | for changeset in args:
91 | for change in changeset:
92 | key = self.get_key_from_change(change)
93 | if key == "ManagedBookmarks":
94 | bookmarks = self.merge_bookmarks(bookmarks, change["value"])
95 | change = {self.KEY_NAME: key, "value": bookmarks}
96 | index[key] = change
97 | return list(index.values())
98 |
99 | def merge_bookmarks(self, a, b):
100 | for elem_b in b:
101 | logger.debug("Processing %s", elem_b)
102 | if "children" in elem_b:
103 | merged = False
104 | for elem_a in a:
105 | if elem_a["name"] == elem_b["name"] and "children" in elem_a:
106 | logger.debug("Processing children of %s", elem_b["name"])
107 | elem_a["children"] = self.merge_bookmarks(
108 | elem_a["children"], elem_b["children"]
109 | )
110 | merged = True
111 | break
112 | if not merged:
113 | a.append(elem_b)
114 | else:
115 | if elem_b not in a:
116 | a.append(elem_b)
117 | logger.debug("Returning %s", a)
118 | return a
119 |
120 |
121 | class FirefoxChangeMerger(BaseChangeMerger):
122 | """
123 | Firefox settings change merger class
124 | """
125 |
126 |
127 | class FirefoxBookmarksChangeMerger(BaseChangeMerger):
128 | """
129 | Firefox bookmarks change merger class
130 | """
131 |
--------------------------------------------------------------------------------
/admin/fleetcommander/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2014 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 |
23 | # Python imports
24 | from __future__ import absolute_import
25 | import logging
26 |
27 | from configparser import ConfigParser, ParsingError
28 |
29 | from . import constants
30 |
31 | logger = logging.getLogger(__name__)
32 |
33 |
34 | def parse_config(config_file=None):
35 | if config_file is None:
36 | config_file = constants.DEFAULT_CONFIG_FILE
37 |
38 | config = ConfigParser()
39 | try:
40 | config.read(config_file)
41 | except IOError:
42 | logger.warning("Could not find configuration file %s", config_file)
43 | except ParsingError:
44 | logger.error("There was an error parsing %s", config_file)
45 | raise
46 | except Exception as e:
47 | logger.error("There was an unknown error parsing %s: %s", config_file, e)
48 | raise e
49 |
50 | section = config["admin"]
51 | args = {
52 | "default_profile_priority": section.getint(
53 | "default_profile_priority", constants.DEFAULT_PROFILE_PRIORITY
54 | ),
55 | "log_level": section.get("log_level", constants.DEFAULT_LOG_LEVEL),
56 | "log_format": section.get("log_format", constants.DEFAULT_LOG_FORMAT),
57 | "data_dir": section.get("data_dir", constants.DEFAULT_DATA_DIR),
58 | "tmp_session_destroy_timeout": section.getint(
59 | "tmp_session_destroy_timeout",
60 | constants.DEFAULT_TMP_SESSION_DESTROY_TIMEOUT,
61 | ),
62 | "auto_quit_timeout": section.getint(
63 | "auto_quit_timeout", constants.DEFAULT_AUTO_QUIT_TIMEOUT
64 | ),
65 | "debug_logger": section.getboolean(
66 | "debug_logger", constants.DEFAULT_DEBUG_LOGGER
67 | ),
68 | "debug_protocol": section.getboolean(
69 | "debug_protocol", constants.DEFAULT_DEBUG_PROTOCOL
70 | ),
71 | }
72 |
73 | return args
74 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | git submodule update --init --recursive
3 | aclocal \
4 | && automake --gnu -a -c \
5 | && autoconf
6 | ./configure $@
7 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(fleet-commander-admin, 0.16.0, aruiz@redhat.com)
2 | AC_COPYRIGHT([Copyright 2014,2015,2016,2017,2018 Red Hat, Inc.])
3 |
4 | AC_PREREQ(2.64)
5 | AM_INIT_AUTOMAKE([no-dist-gzip dist-xz tar-pax])
6 | AM_MAINTAINER_MODE
7 | AC_CONFIG_MACRO_DIR([m4])
8 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
9 |
10 | AC_PATH_PROG([RUNUSER], [runuser], [], [$PATH$PATH_SEPARATOR/sbin])
11 | #AC_PATH_PROG([SSH], [ssh])
12 | #AC_PATH_PROG([SSHKEYGEN], [ssh-keygen])
13 | #AC_PATH_PROG([SSHKEYSCAN], [ssh-keyscan])
14 | AC_PATH_PROG([MKDIR], [mkdir])
15 |
16 | if test x$RUNUSER = x ; then
17 | AC_MSG_ERROR([Could not find runuser])
18 | fi
19 | #if test x$SSH = x ; then
20 | # AC_MSG_ERROR([Could not find ssh])
21 | #fi
22 | #if test x$SSHKEYGEN = x ; then
23 | # AC_MSG_ERROR([Could not find ssh-keygen])
24 | #fi
25 | #if test x$SSHKEYSCAN = x ; then
26 | # AC_MSG_ERROR([Could not find ssh-keyscan])
27 | #fi
28 |
29 | PKG_PROG_PKG_CONFIG
30 |
31 | dnl ------------------
32 | dnl - udev directories
33 | dnl ------------------
34 |
35 | PKG_CHECK_EXISTS([udev], [], [AC_MSG_ERROR([udev devel package not found])])
36 | AC_ARG_WITH([udevrulesdir],
37 | [AS_HELP_STRING([--with-udevrulesdir=DIR],
38 | [Directory for udev rules])],
39 | [udevrulesdir=$with_udevrulesdir],
40 | [udevrulesdir=$($PKG_CONFIG --variable=udevdir udev)/rules.d])
41 | AC_SUBST([udevrulesdir])
42 |
43 | ################
44 | # Dependencies #
45 | ################
46 |
47 | AM_PATH_PYTHON([3],, [:])
48 | AC_PYTHON_MODULE([pexpect], [mandatory])
49 | AC_PYTHON_MODULE([dbus], [mandatory])
50 | AC_PYTHON_MODULE([gi], [mandatory])
51 | AC_PYTHON_MODULE([libvirt], [mandatory])
52 | AC_PYTHON_MODULE([dbusmock])
53 |
54 | # libexecdir expansion for .desktop file
55 | # TODO: Make xdgconfigdir parametric
56 | privlibexecdir='${libexecdir}'
57 | xdgconfigdir='${sysconfdir}'/xdg
58 | adminstatedir='${localstatedir}'/lib/fleet-commander-admin
59 | databasefile='${localstatedir}'/lib/fleet-commander-admin/database.db
60 | fchomedir='${localstatedir}'/lib/fleet-commander
61 | fcadmindir='${datarootdir}'/fleet-commander-admin
62 | fcpythondir='${datarootdir}'/fleet-commander-admin/python
63 | fcloggerdir='${datarootdir}'/fleet-commander-logger
64 | fcloggerpythondir='${datarootdir}'/fleet-commander-logger/python
65 | fcconfigfile='${sysconfdir}'/xdg/fleet-commander-admin.conf
66 | cockpitdir='${datarootdir}'/cockpit
67 | mozillaextensionsdir='${datarootdir}'/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
68 | nativemessagingdir='${libdir}'/mozilla/native-messaging-hosts
69 |
70 | # default runtime configuration
71 | DEFAULT_PROFILE_PRIORITY='50'
72 | DEFAULT_LOG_LEVEL='warning'
73 | DEFAULT_LOG_FORMAT='%(name)s: [%(levelname)s] %(message)s'
74 | DEFAULT_TMP_SESSION_DESTROY_TIMEOUT='60'
75 | DEFAULT_AUTO_QUIT_TIMEOUT='60'
76 | DEFAULT_DEBUG_LOGGER='False'
77 | DEFAULT_DEBUG_PROTOCOL='False'
78 |
79 | AC_SUBST(privlibexecdir)
80 | AC_SUBST(xdgconfigdir)
81 | AC_SUBST(adminstatedir)
82 | AC_SUBST(databasefile)
83 | AC_SUBST(fchomedir)
84 | AC_SUBST(fcadmindir)
85 | AC_SUBST(cockpitdir)
86 | AC_SUBST(fcpythondir)
87 | AC_SUBST(fcloggerdir)
88 | AC_SUBST(fcloggerpythondir)
89 | AC_SUBST(fcconfigfile)
90 | AC_SUBST(mozillaextensionsdir)
91 | AC_SUBST(nativemessagingdir)
92 | AC_SUBST(DEFAULT_PROFILE_PRIORITY)
93 | AC_SUBST(DEFAULT_LOG_LEVEL)
94 | AC_SUBST(DEFAULT_LOG_FORMAT)
95 | AC_SUBST(DEFAULT_TMP_SESSION_DESTROY_TIMEOUT)
96 | AC_SUBST(DEFAULT_AUTO_QUIT_TIMEOUT)
97 | AC_SUBST(DEFAULT_DEBUG_LOGGER)
98 | AC_SUBST(DEFAULT_DEBUG_PROTOCOL)
99 |
100 | AS_AC_EXPAND(XDGCONFIGDIR, "$xdgconfigdir")
101 | AS_AC_EXPAND(PRIVLIBEXECDIR, "$privlibexecdir")
102 | AS_AC_EXPAND(ADMINSTATEDIR, "$adminstatedir")
103 | AS_AC_EXPAND(DATABASEFILE, "$databasefile")
104 | AS_AC_EXPAND(FCHOMEDIR, "$fchomedir")
105 | AS_AC_EXPAND(FCADMINDIR, "$fcadmindir")
106 | AS_AC_EXPAND(COCKPITDIR, "$cockpitdir")
107 | AS_AC_EXPAND(FCPYTHONDIR, "$fcpythondir")
108 | AS_AC_EXPAND(FCLOGGERDIR, "$fcloggerpythondir")
109 | AS_AC_EXPAND(FCLOGGERPYTHONDIR, "$fcloggerpythondir")
110 | AS_AC_EXPAND(FCCONFIGFILE, "$fcconfigfile")
111 | AS_AC_EXPAND(MOZILLAEXTENSIONSDIR, "$mozillaextensionsdir")
112 | AS_AC_EXPAND(NATIVEMESSAGINGDIR, "$nativemessagingdir")
113 |
114 |
115 | AC_SUBST(SYSTEMUNITDIR)
116 |
117 | AC_OUTPUT([
118 | Makefile
119 | data/Makefile
120 | logger/Makefile
121 | tests/Makefile
122 | admin/Makefile
123 | admin/fleetcommander/constants.py
124 | data/fleet-commander-logger.desktop
125 | data/fleet-commander-admin.conf
126 | data/org.freedesktop.FleetCommander.service
127 | data/fleet-commander-admin
128 | data/fleet-commander-logger
129 | data/firefox-bookmark-fclogger
130 | data/firefox_bookmark_fclogger.json
131 | ])
132 |
--------------------------------------------------------------------------------
/data/81-fleet-commander-logger.rules:
--------------------------------------------------------------------------------
1 | ATTR{name}=="org.freedesktop.FleetCommander.0", MODE="0666"
2 | ATTR{name}=="org.freedesktop.FleetCommander.1", MODE="0666"
3 |
--------------------------------------------------------------------------------
/data/Makefile.am:
--------------------------------------------------------------------------------
1 | fleet_commander_logger_desktopdir = ${sysconfdir}/xdg/autostart
2 | fleet_commander_logger_desktop_in_files = fleet-commander-logger.desktop.in
3 | fleet_commander_logger_desktop_DATA = fleet-commander-logger.desktop
4 |
5 | fleet_commander_admin_configdir = ${sysconfdir}/xdg/
6 | fleet_commander_admin_config_in_files = fleet-commander-admin.conf.in
7 | fleet_commander_admin_config_DATA = fleet-commander-admin.conf
8 |
9 | fleet_commander_dbus_servicedir = ${datarootdir}/dbus-1/services/
10 | fleet_commander_dbus_service_in_files = org.freedesktop.FleetCommander.service.in
11 | fleet_commander_dbus_service_DATA = org.freedesktop.FleetCommander.service
12 |
13 | fleet_commander_goa_providersdir = ${fcadmindir}
14 | fleet_commander_goa_providers_DATA = fc-goa-providers.ini
15 |
16 | fleet_commander_chromium_policiesdir = ${datarootdir}/fleet-commander-logger
17 | fleet_commander_chromium_policies_DATA = fc-chromium-policies.json
18 |
19 | fleet_commander_udev_rulesdir = ${udevrulesdir}
20 | fleet_commander_udev_rules_DATA = 81-fleet-commander-logger.rules
21 |
22 | fleet_commander_dbus_shellwrapperdir = ${libexecdir}
23 | fleet_commander_dbus_shellwrapper_in_files = fleet-commander-admin.in
24 | fleet_commander_dbus_shellwrapper_DATA = fleet-commander-admin
25 |
26 | fleet_commander_logger_shellwrapperdir = ${libexecdir}
27 | fleet_commander_logger_shellwrapper_in_files = fleet-commander-logger.in
28 | fleet_commander_logger_shellwrapper_DATA = fleet-commander-logger
29 |
30 | fleet_commander_firefox_logger_shellwrapperdir = ${libexecdir}
31 | fleet_commander_firefox_logger_shellwrapper_in_files = firefox-bookmark-fclogger.in
32 | fleet_commander_firefox_logger_shellwrapper_DATA = firefox-bookmark-fclogger
33 |
34 | fleet_commander_firefox_native_manifestdir = ${nativemessagingdir}
35 | fleet_commander_firefox_native_manifest_in_files = firefox_bookmark_fclogger.json.in
36 | fleet_commander_firefox_native_manifest_DATA = firefox_bookmark_fclogger.json
37 |
38 | fleet_commander_metainfodir = ${datarootdir}/metainfo
39 | fleet_commander_metainfo_DATA = org.freedesktop.FleetCommander.admin.metainfo.xml
40 |
41 | pixmapsdir = ${datarootdir}/pixmaps
42 | pixmaps_DATA = fc-admin.png
43 |
44 | EXTRA_DIST = \
45 | $(fleet_commander_logger_desktop_in_files) \
46 | $(fleet_commander_admin_config_in_files) \
47 | $(fleet_commander_dbus_service_in_files) \
48 | $(fleet_commander_goa_providers_DATA) \
49 | $(fleet_commander_chromium_policies_DATA) \
50 | $(fleet_commander_udev_rules_DATA) \
51 | $(fleet_commander_dbus_shellwrapper_in_files) \
52 | $(fleet_commander_logger_shellwrapper_in_files) \
53 | $(fleet_commander_firefox_logger_shellwrapper_in_files) \
54 | $(fleet_commander_firefox_native_manifest_in_files) \
55 | $(fleet_commander_metainfo_DATA) \
56 | $(pixmaps_DATA)
57 |
58 | CLEANFILES = \
59 | $(fleet_commander_logger_desktop_DATA) \
60 | $(fleet_commander_admin_config_DATA) \
61 | $(fleet_commander_firefox_native_manifest_DATA)
62 |
63 |
--------------------------------------------------------------------------------
/data/fc-admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/data/fc-admin.png
--------------------------------------------------------------------------------
/data/fc-goa-providers.ini:
--------------------------------------------------------------------------------
1 | [Provider google]
2 | ProviderName=Google
3 | MailEnabled=true
4 | CalendarEnabled=true
5 | ContactsEnabled=true
6 | DocumentsEnabled=true
7 | PhotosEnabled=true
8 | FilesEnabled=true
9 | PrintersEnabled=true
10 |
11 | [Provider owncloud]
12 | ProviderName=ownCloud
13 | CalendarEnabled=true
14 | ContactsEnabled=true
15 | DocumentsEnabled=true
16 | FilesEnabled=true
17 |
18 | [Provider facebook]
19 | ProviderName=Facebook
20 | PhotosEnabled=true
21 | MapsEnabled=true
22 |
23 | [Provider flickr]
24 | ProviderName=Flickr
25 | PhotosEnabled=true
26 |
27 | [Provider windows_live]
28 | ProviderName=Microsoft Account
29 | MailEnabled=true
30 | DocumentsEnabled=true
31 |
32 | [Provider pocket]
33 | ProviderName=Pocket
34 | ReadLaterEnabled=true
35 |
36 | [Provider foursquare]
37 | ProviderName=Foursquare
38 | MapsEnabled=true
39 |
40 | [Provider exchange]
41 | ProviderName=Microsoft Exchange
42 | MailEnabled=true
43 | CalendarEnabled=true
44 | ContactsEnabled=true
45 |
46 | [Provider imap_smtp]
47 | ProviderName=IMAP and SMTP
48 | Enabled=true
49 |
50 | [Provider kerberos]
51 | ProviderName=Enterprise Login (Kerberos)
52 | TicketingEnabled=true
53 |
--------------------------------------------------------------------------------
/data/firefox-bookmark-fclogger.in:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | /usr/bin/env @PYTHON@ @FCLOGGERPYTHONDIR@/firefox_bookmark_fclogger.py $@
--------------------------------------------------------------------------------
/data/firefox_bookmark_fclogger.json.in:
--------------------------------------------------------------------------------
1 | {
2 | "name": "firefox_bookmark_fclogger",
3 | "description": "Fleet Commander Firefox Bookmarks Logger native aplication",
4 | "type": "stdio",
5 | "path": "@PRIVLIBEXECDIR@/firefox-bookmark-fclogger",
6 | "allowed_extensions": ["{c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}"]
7 | }
8 |
--------------------------------------------------------------------------------
/data/fleet-commander-admin.conf.in:
--------------------------------------------------------------------------------
1 | ############
2 | ## defaults:
3 | ############
4 | # [admin]
5 | #
6 | # data_dir = @FCADMINDIR@
7 | #
8 | # default_profile_priority = @DEFAULT_PROFILE_PRIORITY@
9 | #
10 | ## Set both the log level of Python logging events and JavaScript events.
11 | ## Note: previously also set the log level of spice-html5 events, but as of
12 | ## spice-html5 0.2(switch to JS modules) it should be set directly in
13 | ## @COCKPITDIR@/fleet-commander-admin/js/spice-html5/src/utils.js
14 | # log_level = @DEFAULT_LOG_LEVEL@
15 | #
16 | ## Set the format of Python logging records.
17 | # log_format = @DEFAULT_LOG_FORMAT@
18 | #
19 | ## Toggle the forwarding of logging events of Logger(within libvirt domain)
20 | ## into web browser console.
21 | ## Possible values: same as
22 | ## https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.getboolean
23 | # debug_logger = @DEFAULT_DEBUG_LOGGER@
24 | #
25 | ## Toggle the logging of FC Logger protocol(JavaScript part) into web browser
26 | ## console.
27 | ## Possible values: same as
28 | ## https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.getboolean
29 | # debug_protocol = @DEFAULT_DEBUG_PROTOCOL@
30 | #
31 | ## Inactivity of user(via web browser) after which FC session will be closed.
32 | # tmp_session_destroy_timeout = @DEFAULT_TMP_SESSION_DESTROY_TIMEOUT@
33 | #
34 | ## Inactivity of FC dbus after which FC dbus service will be stopped.
35 | # auto_quit_timeout = @DEFAULT_AUTO_QUIT_TIMEOUT@
36 |
37 | [admin]
38 |
--------------------------------------------------------------------------------
/data/fleet-commander-admin.in:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | PYTHONPATH=@FCPYTHONDIR@ @PYTHON@ -m fleetcommander.fcdbus --configuration @XDGCONFIGDIR@/fleet-commander-admin.conf
3 |
--------------------------------------------------------------------------------
/data/fleet-commander-logger.desktop.in:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=Fleet Commander Session Logger
4 | Icon=preferences-desktop-screensaver
5 | Exec=@PRIVLIBEXECDIR@/fleet-commander-logger
6 | OnlyShowIn=GNOME;MATE;
7 | NoDisplay=true
8 | X-GNOME-Autostart-Phase=Applications
9 | X-GNOME-Autostart-Notify=true
10 |
--------------------------------------------------------------------------------
/data/fleet-commander-logger.in:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | @PYTHON@ @FCLOGGERPYTHONDIR@/fleet_commander_logger.py $@
4 |
--------------------------------------------------------------------------------
/data/org.freedesktop.FleetCommander.admin.metainfo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.freedesktop.FleetCommander.admin
4 | CC0-1.0
5 | Fleet Commander
6 | /usr/share/pixmaps/fc-admin.png
7 | Manage desktop configuration for a large network
8 |
9 |
10 | Fleet Commander is an application that allows you to manage the
11 | desktop configuration of a large network of users and
12 | workstations/laptops. It is primarily targeted to Linux systems
13 | based on the GNOME desktop.
14 |
15 |
16 | org.cockpit_project.cockpit
17 | fleet-commander-admin
18 | https://fleet-commander.org/
19 |
20 |
--------------------------------------------------------------------------------
/data/org.freedesktop.FleetCommander.service.in:
--------------------------------------------------------------------------------
1 | # DBus service activation config
2 | [D-BUS Service]
3 | Name=org.freedesktop.FleetCommander
4 | Exec=@PRIVLIBEXECDIR@/fleet-commander-admin
5 |
--------------------------------------------------------------------------------
/logger/Makefile.am:
--------------------------------------------------------------------------------
1 | fleet_commander_loggerdir = ${fcloggerpythondir}
2 | fleet_commander_logger_SCRIPTS = \
3 | fleet_commander_logger.py \
4 | firefox_bookmark_fclogger.py
5 |
6 | fclogger_extension_firefoxdir = ${mozillaextensionsdir}
7 | fclogger_extension_firefox_DATA = {c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}.xpi
8 |
9 |
10 | EXTRA_DIST = \
11 | $(fleet_commander_logger_SCRIPTS) \
12 | $(fclogger_extension_firefox_DATA)
--------------------------------------------------------------------------------
/logger/firefox-extension/bookmarklogger.js:
--------------------------------------------------------------------------------
1 | /*global browser */
2 |
3 | "use strict";
4 |
5 | /***************************************************
6 | Native port connection
7 | ***************************************************/
8 |
9 | var port = browser.runtime.connectNative("firefox_bookmark_fclogger");
10 |
11 | port.onMessage.addListener(function (response) {
12 | console.log("FC - Received from native app: " + response);
13 | });
14 |
15 | port.onDisconnect.addListener(function (data) {
16 | console.log("FC -Disconnected", data);
17 | });
18 |
19 | /**************************************************
20 | Helpers
21 | **************************************************/
22 |
23 | // Communicate bookmarks to native script
24 | function sendBookmark(bookmark) {
25 | if (bookmark.folder === '') {
26 | bookmark.folder = null;
27 | }
28 | console.log('Submitting bookmark to logger: ' + bookmark);
29 | port.postMessage(bookmark);
30 | }
31 |
32 | // Get bookmark information
33 | function getBookmarkData(action, id) {
34 |
35 | var bookmark_object = {
36 | action: action,
37 | id: id,
38 | title: null,
39 | url: null,
40 | folder: null,
41 | placement: 'menu' // By default, we place bookmarks in menu
42 | };
43 |
44 | // Promise reject method
45 | function onRejected(error) {
46 | console.log('Unable to get bookmark data: ' + error);
47 | }
48 |
49 | // Promise fullfill method
50 | function onFulfilled(bookmark_data) {
51 | var bookmark = bookmark_data[0];
52 |
53 | // Setup initial data if not already set
54 | if (!this.title) {
55 | this.title = bookmark.title;
56 | }
57 |
58 | if (!this.url) {
59 | this.url = bookmark.url;
60 | }
61 |
62 | // If this bookmark has a parent we need to iterate
63 | console.log("PARENT: ", bookmark.parentId);
64 | if (bookmark.parentId && bookmark.parentId !== 'root________') {
65 | if (bookmark.parentId === 'toolbar_____') {
66 | this.placement = 'toolbar';
67 | }
68 | if (this.folder === null) {
69 | // This is the bookmark title, not the folder
70 | this.folder = '';
71 | } else {
72 | this.folder = bookmark.title + '/' + this.folder;
73 | }
74 |
75 | browser.bookmarks.get(bookmark.parentId).then(
76 | onFulfilled.bind(this),
77 | onRejected.bind(this)
78 | );
79 | } else {
80 | // We reached bookmarks root. Submit this bookmark information.
81 | console.log('Bookmark information: ' + this);
82 | sendBookmark(this);
83 | }
84 | }
85 |
86 | // Initiate promise chain to get bookmark folder info
87 | browser.bookmarks.get(bookmark_object.id).then(
88 | onFulfilled.bind(bookmark_object),
89 | onRejected.bind(bookmark_object)
90 | );
91 | }
92 |
93 |
94 | /***************************************************
95 | Bookmark Event listeners
96 | ***************************************************/
97 |
98 | function bookmarkCreated(id, bookmark_info) {
99 | console.log('Created bookmark ' + id + ': ', bookmark_info);
100 | getBookmarkData('add', id);
101 | }
102 |
103 | function bookmarkRemoved(id, bookmark_info) {
104 | console.log('Created bookmark ' + id + ': ', bookmark_info);
105 | var bmark = {
106 | action: 'remove',
107 | id: id,
108 | };
109 | sendBookmark(bmark);
110 | }
111 |
112 | function bookmarkChanged(id, bookmark_info) {
113 | console.log('Changed bookmark ' + id + ': ', bookmark_info);
114 | getBookmarkData('change', id);
115 | }
116 |
117 | function bookmarkMoved(id, bookmark_info) {
118 | console.log('Moved bookmark ' + id + ': ', bookmark_info);
119 | getBookmarkData('move', id);
120 | }
121 |
122 | // Initialize listeners
123 | browser.bookmarks.onCreated.addListener(bookmarkCreated);
124 | browser.bookmarks.onRemoved.addListener(bookmarkRemoved);
125 | browser.bookmarks.onChanged.addListener(bookmarkChanged);
126 | browser.bookmarks.onMoved.addListener(bookmarkMoved);
127 |
--------------------------------------------------------------------------------
/logger/firefox-extension/icons/fc-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/logger/firefox-extension/icons/fc-48.png
--------------------------------------------------------------------------------
/logger/firefox-extension/icons/fc-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/logger/firefox-extension/icons/fc-96.png
--------------------------------------------------------------------------------
/logger/firefox-extension/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "manifest_version": 2,
4 | "name": "Fleet Commander logger",
5 | "version": "1.0.4",
6 |
7 | "description": "Enables bookmark monitoring for Fleet Commander logger",
8 |
9 | "permissions": [
10 | "bookmarks",
11 | "nativeMessaging"
12 | ],
13 |
14 | "browser_specific_settings": {
15 | "gecko": {
16 | "id": "{c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}",
17 | "strict_min_version": "60.0"
18 | }
19 | },
20 |
21 | "icons": {
22 | "48": "icons/fc-48.png",
23 | "96": "icons/fc-96.png"
24 | },
25 |
26 | "background": {
27 | "scripts": ["bookmarklogger.js"]
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/logger/firefox_bookmark_fclogger.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2019 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Author: Oliver Gutiérrez
20 |
21 | import sys
22 | import json
23 | import struct
24 | import time
25 | import logging
26 | import dbus
27 | from functools import wraps
28 |
29 |
30 | DBUS_BUS_NAME = "org.freedesktop.FleetCommanderLogger"
31 | DBUS_OBJECT_PATH = "/org/freedesktop/FleetCommanderLogger"
32 | DBUS_INTERFACE_NAME = "org.freedesktop.FleetCommanderLogger"
33 |
34 |
35 | def connected_to_dbus_service(f):
36 | @wraps(f)
37 | def wrapped(obj, *args, **kwargs):
38 | if obj.iface is None:
39 | obj.connect()
40 | if obj.iface is None:
41 | logging.error("Not connected to FC Logger dbus service")
42 | return None
43 | r = f(obj, *args, **kwargs)
44 | return r
45 |
46 | return wrapped
47 |
48 |
49 | class FleetCommanderLoggerDbusClient:
50 | """
51 | Fleet commander logger dbus client
52 | """
53 |
54 | DEFAULT_BUS = dbus.SessionBus
55 | CONNECTION_TIMEOUT = 1
56 |
57 | def __init__(self, bus=None):
58 | """
59 | Class initialization
60 | """
61 | self.obj = None
62 | self.iface = None
63 |
64 | if bus is None:
65 | bus = self.DEFAULT_BUS()
66 | self.bus = bus
67 |
68 | def connect(self):
69 | """
70 | Connect to dbus service
71 | """
72 | logging.debug("Connecting to FC Logger dbus service")
73 | t = time.time()
74 | while time.time() - t < self.CONNECTION_TIMEOUT:
75 | try:
76 | self.obj = self.bus.get_object(DBUS_BUS_NAME, DBUS_OBJECT_PATH)
77 | self.iface = dbus.Interface(
78 | self.obj, dbus_interface=DBUS_INTERFACE_NAME
79 | )
80 | return
81 | except Exception:
82 | logging.debug("Can't connect to FC Logger dbus service")
83 |
84 | @connected_to_dbus_service
85 | def firefox_bookmark_update(self, bookmark_id, data):
86 | return self.iface.FirefoxBookmarkUpdate(bookmark_id, data)
87 |
88 | @connected_to_dbus_service
89 | def firefox_bookmark_remove(self, bookmark_id):
90 | return self.iface.FirefoxBookmarkRemove(bookmark_id)
91 |
92 |
93 | class FirefoxExtensionMessagingHelper:
94 | """
95 | Firefox messaging helper class
96 | """
97 |
98 | def __init__(self):
99 | # Set shortcuts for standard input and output buffers
100 | try:
101 | # Python 3
102 | self.stdin_buffer = sys.stdin.buffer
103 | self.stdout_buffer = sys.stdout.buffer
104 | except AttributeError:
105 | # Python 2
106 | self.stdin_buffer = sys.stdin
107 | self.stdout_buffer = sys.stdout
108 |
109 | def get_message(self):
110 | """
111 | Read a message from stdin and decode it
112 | """
113 | raw_length = self.stdin_buffer.read(4)
114 | if len(raw_length) == 0:
115 | sys.exit(0)
116 | message_length = struct.unpack("@I", raw_length)[0]
117 | message = self.stdin_buffer.read(message_length).decode("utf-8")
118 | return json.loads(message)
119 |
120 | def encode_message(self, content):
121 | """
122 | Encode a message for transmission
123 | """
124 | encoded_content = json.dumps(content).encode("utf-8")
125 | encoded_length = struct.pack("@I", len(encoded_content))
126 | return {"length": encoded_length, "content": encoded_content}
127 |
128 | def send_message(self, message):
129 | """
130 | Send an encoded message to stdout
131 | """
132 | encoded_message = self.encode_message(message)
133 | self.stdout_buffer.write(encoded_message["length"])
134 | self.stdout_buffer.write(encoded_message["content"])
135 | self.stdout_buffer.flush()
136 |
137 |
138 | extension = FirefoxExtensionMessagingHelper()
139 | fclogger = FleetCommanderLoggerDbusClient()
140 |
141 |
142 | while True:
143 | message = extension.get_message()
144 | bookmark_id = message["id"]
145 | if message["action"] in ["add", "change", "move"]:
146 | extension.send_message(
147 | "Received bookmark {} for bookmark id {}".format(
148 | message["action"], bookmark_id
149 | )
150 | )
151 | logging.debug(
152 | "Sending bookmark %s command to FC Logger dbus service", message["action"]
153 | )
154 | fclogger.firefox_bookmark_update(bookmark_id, json.dumps(message))
155 | elif message["action"] == "remove":
156 | extension.send_message(
157 | "Received bookmark remove command for bookmark id {}".format(bookmark_id)
158 | )
159 | fclogger.firefox_bookmark_remove(bookmark_id)
160 | else:
161 | logging.debug("Unknown action received from extension")
162 |
--------------------------------------------------------------------------------
/logger/{c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/logger/{c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}.xpi
--------------------------------------------------------------------------------
/m4/as-ac-expand.m4:
--------------------------------------------------------------------------------
1 | dnl as-ac-expand.m4 0.2.0 -*- autoconf -*-
2 | dnl autostars m4 macro for expanding directories using configure's prefix
3 |
4 | dnl (C) 2003, 2004, 2005 Thomas Vander Stichele
5 |
6 | dnl Copying and distribution of this file, with or without modification,
7 | dnl are permitted in any medium without royalty provided the copyright
8 | dnl notice and this notice are preserved.
9 |
10 | dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
11 |
12 | dnl example:
13 | dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
14 | dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
15 |
16 | AC_DEFUN([AS_AC_EXPAND],
17 | [
18 | EXP_VAR=[$1]
19 | FROM_VAR=[$2]
20 |
21 | dnl first expand prefix and exec_prefix if necessary
22 | prefix_save=$prefix
23 | exec_prefix_save=$exec_prefix
24 |
25 | dnl if no prefix given, then use /usr/local, the default prefix
26 | if test "x$prefix" = "xNONE"; then
27 | prefix="$ac_default_prefix"
28 | fi
29 | dnl if no exec_prefix given, then use prefix
30 | if test "x$exec_prefix" = "xNONE"; then
31 | exec_prefix=$prefix
32 | fi
33 |
34 | full_var="$FROM_VAR"
35 | dnl loop until it doesn't change anymore
36 | while true; do
37 | new_full_var="`eval echo $full_var`"
38 | if test "x$new_full_var" = "x$full_var"; then break; fi
39 | full_var=$new_full_var
40 | done
41 |
42 | dnl clean up
43 | full_var=$new_full_var
44 | AC_SUBST([$1], "$full_var")
45 |
46 | dnl restore prefix and exec_prefix
47 | prefix=$prefix_save
48 | exec_prefix=$exec_prefix_save
49 | ])
50 |
51 |
--------------------------------------------------------------------------------
/package-requirements.txt:
--------------------------------------------------------------------------------
1 | autoconf
2 | automake
3 | autoconf-archive
4 | libvirt-python
5 | python-dbusmock
6 | python-gobject
7 | dbus-python
8 | rpm-build
9 | python-pexpect
10 |
--------------------------------------------------------------------------------
/pylint_plugins.py:
--------------------------------------------------------------------------------
1 | """ Plugin to teach Pylint about FreeIPA API
2 | """
3 |
4 | import textwrap
5 |
6 | from astroid import MANAGER
7 | from astroid.builder import AstroidBuilder
8 |
9 |
10 | def register(linter):
11 | pass
12 |
13 |
14 | AstroidBuilder(MANAGER).string_build(
15 | textwrap.dedent(
16 | """
17 | from ipalib import api
18 | from ipalib import plugable
19 |
20 | api.Backend = plugable.APINameSpace(api, None)
21 | api.Command = plugable.APINameSpace(api, None)
22 | """
23 | )
24 | )
25 |
26 | AstroidBuilder(MANAGER).string_build(
27 | textwrap.dedent(
28 | """\
29 | import unittest
30 | from tests.test_libvirt_controller import TestLibVirtController
31 |
32 | TestLibVirtController.assertTrue = unittest.TestCase.assertTrue
33 | TestLibVirtController.assertFalse = unittest.TestCase.assertFalse
34 | TestLibVirtController.assertEqual = unittest.TestCase.assertEqual
35 | TestLibVirtController.assertListEqual = unittest.TestCase.assertListEqual
36 | TestLibVirtController.assertDictEqual = unittest.TestCase.assertDictEqual
37 | """
38 | )
39 | )
40 |
--------------------------------------------------------------------------------
/pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 | persistent=no
3 |
4 | extension-pkg-whitelist=
5 | _ldap,
6 | samba.dcerpc.security,
7 | samba.samba3.param,
8 | samba.credentials,
9 |
10 | [MESSAGES CONTROL]
11 | enable=
12 | all,
13 | python3,
14 | useless-suppression,
15 |
16 | disable=
17 | bad-inline-option,
18 | c-extension-no-member,
19 | deprecated-pragma,
20 | file-ignored,
21 | locally-disabled,
22 | raw-checker-failed,
23 | suppressed-message,
24 | use-symbolic-message-instead,
25 | bad-continuation,
26 | bad-indentation,
27 | bad-whitespace,
28 | broad-except,
29 | dangerous-default-value,
30 | duplicate-code,
31 | fixme,
32 | invalid-name,
33 | line-too-long,
34 | missing-docstring,
35 | no-absolute-import,
36 | no-self-use,
37 | protected-access,
38 | raise-missing-from,
39 | redefined-builtin,
40 | redefined-outer-name,
41 | super-init-not-called,
42 | superfluous-parens,
43 | too-few-public-methods,
44 | too-many-arguments,
45 | too-many-branches,
46 | too-many-instance-attributes,
47 | too-many-lines,
48 | too-many-locals,
49 | too-many-nested-blocks,
50 | too-many-public-methods,
51 | too-many-return-statements,
52 | too-many-statements,
53 | trailing-newlines,
54 | trailing-whitespace,
55 | ungrouped-imports,
56 | unused-argument,
57 | wrong-import-order,
58 | wrong-import-position,
59 | consider-using-with, # pylint 2.8.0, contextmanager is not mandatory
60 | consider-using-max-builtin, # pylint 2.8.0, code can be more readable
61 | consider-using-min-builtin, # pylint 2.8.0, code can be more readable
62 | consider-using-f-string, # pylint 2.11.0, format can be more readable
63 |
64 | [REPORTS]
65 | output-format=colorized
66 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | line-length = 88
3 | exclude = '''
4 | (
5 | /(
6 | \.git
7 | | dist
8 | | rpmbuild
9 | )/
10 | )
11 | '''
12 |
--------------------------------------------------------------------------------
/tests/Makefile.am:
--------------------------------------------------------------------------------
1 | NULL =
2 |
3 | TESTS_ENVIRONMENT = \
4 | export PATH=$(abs_top_srcdir)/tests/tools:$(abs_top_srcdir)/tests:$(PATH); \
5 | export TOPSRCDIR=$(abs_top_srcdir); \
6 | export FC_TESTING=true; \
7 | export XDG_DATA_DIRS=$(abs_top_srcdir)/tests/data/; \
8 | export PYTHON=@PYTHON@; \
9 | export PYTHONPATH=$(abs_top_srcdir):$(abs_top_srcdir)/admin; \
10 | export PYTHONPATH=$${PYTHONPATH}:$(abs_top_srcdir)/logger; \
11 | $(NULL)
12 |
13 | TESTS = \
14 | test_database.py \
15 | test_freeipa.py \
16 | test_fcad.py \
17 | test_sshcontroller.py \
18 | test_mergers.py \
19 | test_logger_dconf.sh \
20 | test_logger_connmgr.py \
21 | test_logger_nm.sh \
22 | test_logger_chromium.py \
23 | test_logger_firefox.py \
24 | test_logger_main.py \
25 | test_libvirt_controller.py \
26 | test_fcdbus.sh \
27 | $(NULL)
28 |
29 | EXTRA_DIST = \
30 | $(TESTS) \
31 | python-wrapper.sh \
32 | __init__.py \
33 | freeipamock.py \
34 | libvirtmock.py \
35 | ldapmock.py \
36 | smbmock.py \
37 | directorymock.py \
38 | fcdbusclient.py \
39 | _mock_dbus.py \
40 | _logger_test_suite.py \
41 | _wait_for_name.py \
42 | _logger_nm.py \
43 | _mock_nm_dbus.py \
44 | _fcdbus_tests.py \
45 | _mock_realmd_dbus.py \
46 | test_fcdbus_service.py \
47 | data/test.gschema.xml \
48 | data/libvirt_domain-orig.xml \
49 | data/libvirt_domain-modified-html5.xml \
50 | data/libvirt_domain-modified-html5-debug.xml \
51 | data/libvirt_domain-modified-direct.xml \
52 | data/libvirt_domain-modified-direct-debug.xml \
53 | data/libvirt_domain-modified-direct-plain.xml \
54 | data/libvirt_domain-modified-direct-plain-debug.xml \
55 | data/libvirt_domain-nospice.xml \
56 | data/fc_goa_providers_test.ini \
57 | data/fleet-commander-logger/fc-chromium-policies.json \
58 | tools/ssh \
59 | tools/ssh-keygen \
60 | tools/ssh-keyscan \
61 | tools/ssh-session-mock \
62 | $(NULL)
63 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2020 FleetCommander Contributors see COPYING for license
3 | #
4 | """Common tests' assumptions."""
5 |
6 | SSH_TUNNEL_OPEN_PARMS = " ".join(
7 | [
8 | "{optional_args}",
9 | "-i",
10 | "{private_key_file}",
11 | "-o",
12 | "PreferredAuthentications=publickey",
13 | "-o",
14 | "PasswordAuthentication=no",
15 | "-o",
16 | "ExitOnForwardFailure=yes",
17 | "-o",
18 | "ControlMaster=yes",
19 | "-S",
20 | "{user_home}/.ssh/fc-control-ssh-tunnel.socket",
21 | "{username}@{hostname}",
22 | "-p",
23 | "{port}",
24 | "-L {local_forward}",
25 | "-N",
26 | "-f",
27 | ]
28 | )
29 |
30 | SSH_REMOTE_COMMAND_PARMS = " ".join(
31 | [
32 | "{optional_args}",
33 | "-i",
34 | "{private_key_file}",
35 | "-o",
36 | "PreferredAuthentications=publickey",
37 | "-o",
38 | "PasswordAuthentication=no",
39 | "{username}@{hostname}",
40 | "-p",
41 | "{port}",
42 | "{command}",
43 | ]
44 | )
45 | SSH_TUNNEL_CLOSE_PARMS = " ".join(
46 | [
47 | "{optional_args}",
48 | "-i",
49 | "{private_key_file}",
50 | "-o",
51 | "PreferredAuthentications=publickey",
52 | "-o",
53 | "PasswordAuthentication=no",
54 | "{username}@{hostname}",
55 | "-p",
56 | "{port}",
57 | "-S",
58 | "{user_home}/.ssh/fc-control-ssh-tunnel.socket",
59 | "-O",
60 | "exit",
61 | ]
62 | )
63 |
--------------------------------------------------------------------------------
/tests/_mock_dbus.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | import dbus.service
3 | import dbusmock
4 | import dbus.mainloop.glib
5 | from gi.repository import GLib
6 |
7 | ml = GLib.MainLoop()
8 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
9 | bus = dbusmock.testcase.DBusTestCase.get_dbus()
10 | bus.add_signal_receiver(
11 | ml.quit,
12 | signal_name="Disconnected",
13 | path="/org/freedesktop/DBus/Local",
14 | dbus_interface="org.freedesktop.DBus.Local",
15 | )
16 |
17 |
18 | fdo_bus = dbus.service.BusName(
19 | "org.freedesktop.ScreenSaver",
20 | bus,
21 | allow_replacement=True,
22 | replace_existing=True,
23 | do_not_queue=True,
24 | )
25 |
26 | screensaver = dbusmock.mockobject.DBusMockObject(
27 | fdo_bus, "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", {}
28 | )
29 | screensaver.AddMethods(
30 | "org.freedesktop.ScreenSaver",
31 | [
32 | ("Inhibit", "ss", "u", "ret = 9191"),
33 | ("UnInhibit", "u", "", ""),
34 | ],
35 | )
36 |
37 | dconf_bus = dbus.service.BusName(
38 | "ca.desrt.dconf",
39 | bus,
40 | allow_replacement=True,
41 | replace_existing=True,
42 | do_not_queue=True,
43 | )
44 |
45 | dconf = dbusmock.mockobject.DBusMockObject(
46 | dconf_bus, "/ca/desrt/dconf/Writer/user", "ca.desrt.dconf.Writer", {}
47 | )
48 | dconf.AddMethod(
49 | "ca.desrt.dconf.Writer",
50 | "Change",
51 | "ay",
52 | "s",
53 | 'self.EmitSignal("ca.desrt.dconf.Writer", "Notify", "sass", ["/test/", ["test",], "tag"]);ret = "tag"',
54 | )
55 | dconf.AddMethod(
56 | "ca.desrt.dconf.Writer",
57 | "ChangeCommon",
58 | "",
59 | "",
60 | 'self.EmitSignal("ca.desrt.dconf.Writer", "Notify", "sass", ["/reloc/foo/", ["fc-common",], "tag"])',
61 | )
62 | dconf.AddMethod(
63 | "ca.desrt.dconf.Writer",
64 | "ChangeUnique",
65 | "",
66 | "",
67 | 'self.EmitSignal("ca.desrt.dconf.Writer", "Notify", "sass", ["/reloc/foo/", ["fc-unique",], "tag"])',
68 | )
69 | dconf.AddMethod(
70 | "ca.desrt.dconf.Writer",
71 | "ChangeUniqueAndCommon",
72 | "",
73 | "",
74 | 'self.EmitSignal("ca.desrt.dconf.Writer", "Notify", "sass", ["/reloc/foo/", ["fc-unique","fc-common"], "tag"])',
75 | )
76 | dconf.AddMethod(
77 | "ca.desrt.dconf.Writer",
78 | "ChangeLibreOffice",
79 | "",
80 | "",
81 | 'self.EmitSignal("ca.desrt.dconf.Writer", "Notify", "sass", ["/org/libreoffice/registry/somepath/", ["somekey",], "tag"])',
82 | )
83 |
84 | dbusmock.mockobject.objects["/ScreenSaver"] = screensaver
85 | ml.run()
86 |
--------------------------------------------------------------------------------
/tests/_mock_nm_dbus.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import logging
4 | import os
5 |
6 | import dbus.service
7 | import dbusmock
8 | import dbus.mainloop.glib
9 | from gi.repository import GLib
10 |
11 | logger = logging.getLogger(os.path.basename(__file__))
12 |
13 | ml = GLib.MainLoop()
14 |
15 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
16 |
17 | bus = dbusmock.testcase.DBusTestCase.get_dbus()
18 |
19 | bus.add_signal_receiver(
20 | ml.quit,
21 | signal_name="Disconnected",
22 | path="/org/freedesktop/DBus/Local",
23 | dbus_interface="org.freedesktop.DBus.Local",
24 | )
25 |
26 | nm_bus = dbus.service.BusName(
27 | "org.freedesktop.NetworkManager",
28 | bus,
29 | allow_replacement=True,
30 | replace_existing=True,
31 | do_not_queue=True,
32 | )
33 |
34 | if __name__ == "__main__":
35 | logging.basicConfig(level=logging.DEBUG)
36 | logger.debug("Configured and running NetworkManager dbus mock")
37 | ml.run()
38 | logger.debug("Quitting NetworkManager dbus mock")
39 |
--------------------------------------------------------------------------------
/tests/_mock_realmd_dbus.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import logging
4 | import os
5 |
6 | import dbus.service
7 | import dbusmock
8 | import dbus.mainloop.glib
9 | from gi.repository import GLib
10 |
11 | logger = logging.getLogger(os.path.basename(__file__))
12 |
13 | ml = GLib.MainLoop()
14 |
15 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
16 |
17 | bus = dbusmock.testcase.DBusTestCase.get_dbus()
18 |
19 | bus.add_signal_receiver(
20 | ml.quit,
21 | signal_name="Disconnected",
22 | path="/org/freedesktop/DBus/Local",
23 | dbus_interface="org.freedesktop.DBus.Local",
24 | )
25 |
26 | realmd_bus = dbus.service.BusName(
27 | "org.freedesktop.realmd",
28 | bus,
29 | allow_replacement=True,
30 | replace_existing=True,
31 | do_not_queue=True,
32 | )
33 |
34 | # Provider
35 | provider = dbusmock.mockobject.DBusMockObject(
36 | realmd_bus,
37 | "/org/freedesktop/realmd/Sssd",
38 | "org.freedesktop.realmd.Provider",
39 | {"Realms": ["/org/freedesktop/realmd/Sssd/fc_ipa_X"]},
40 | )
41 |
42 | # Realm
43 | realm = dbusmock.mockobject.DBusMockObject(
44 | realmd_bus,
45 | "/org/freedesktop/realmd/Sssd/fc_ipa_X",
46 | "org.freedesktop.realmd.Realm",
47 | {
48 | "Name": "fc.directory",
49 | "Details": [
50 | ("server-software", "active-directory"),
51 | ("client-software", "sssd"),
52 | ],
53 | },
54 | )
55 |
56 |
57 | if __name__ == "__main__":
58 | logging.basicConfig(level=logging.DEBUG)
59 | logging.debug("Configured and running realmd dbus mock")
60 | ml.run()
61 | logging.debug("Quitting realmd dbus mock")
62 |
--------------------------------------------------------------------------------
/tests/_wait_for_name.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | import dbus
3 | import time
4 | import sys
5 |
6 | if __name__ == "__main__":
7 | session = dbus.Bus()
8 | for i in range(20):
9 | for name in session.list_names():
10 | if name == sys.argv[1]:
11 | sys.exit(0)
12 | time.sleep(0.1)
13 | sys.exit(1)
14 |
--------------------------------------------------------------------------------
/tests/azure/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 |
4 | variables:
5 | - template: templates/variables-common.yml
6 | # platform specific variables, links to
7 | - template: templates/variables.yml
8 |
9 | jobs:
10 | - job: Build_and_Unittests
11 | pool:
12 | vmImage: $(VM_IMAGE)
13 | container:
14 | image: $(DOCKER_BUILD_IMAGE)
15 | steps:
16 | - template: templates/${{ variables.PREPARE_BUILD_TEMPLATE }}
17 | - template: templates/${{ variables.PREPARE_LINT_TEMPLATE }}
18 | - template: templates/${{ variables.CONFIGURE_TEMPLATE }}
19 | - script: |
20 | set -e
21 | make pylint
22 | displayName: Pylint sources
23 | - script: |
24 | set -e
25 | make blackcheck
26 | displayName: Black sources
27 | - script: |
28 | set -e
29 | make VERBOSE=1 check
30 | displayName: Run unittests
31 | - script: |
32 | set -e
33 | make eslint
34 | displayName: Lint JavaScript sources
35 | - script: |
36 | set -e
37 | make VERBOSE=1 distcheck
38 | displayName: Run distribute unittests
39 | - template: templates/${{ variables.BUILD_TEMPLATE }}
40 | - template: templates/publish-build.yml
41 | parameters:
42 | artifactName: 'packages-$(Build.BuildId)'
43 | targetPath: $(Build.Repository.LocalPath)/dist
44 | displayName: Publish packages
45 |
--------------------------------------------------------------------------------
/tests/azure/templates/build-fedora.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - script: |
3 | set -e
4 | echo "Running make target 'rpms'"
5 | make rpms
6 | displayName: Build RPM packages
7 |
--------------------------------------------------------------------------------
/tests/azure/templates/configure-fedora.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - script: |
3 | set -e
4 | printf "Configuring project"
5 | git submodule update --init --recursive
6 | autoreconf -ifv
7 | ./configure
8 | displayName: Configure the project
9 |
--------------------------------------------------------------------------------
/tests/azure/templates/prepare-build-fedora.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - script: |
3 | set -e
4 | sudo rm -rf /var/cache/dnf/*
5 | sudo dnf makecache || :
6 | printf "Installing base dev dependencies\n"
7 | sudo dnf install -y \
8 | 'dnf-command(builddep)' \
9 | autoconf \
10 | autoconf-archive \
11 | automake \
12 | gettext-devel \
13 | make \
14 | rpm-build \
15 |
16 | printf "Installing FC dev dependencies\n"
17 | sudo dnf builddep -y \
18 | --skip-broken \
19 | -D "with_check 1" \
20 | --spec fleet-commander-admin.spec \
21 | --best \
22 | --allowerasing \
23 | --setopt=install_weak_deps=False \
24 |
25 | displayName: Prepare build environment
26 |
--------------------------------------------------------------------------------
/tests/azure/templates/prepare-lint-fedora.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - script: |
3 | set -e
4 | printf "Installing pip module\n"
5 | sudo dnf install -y \
6 | python3-pip \
7 |
8 | printf "Installing latest Python lint dependencies\n"
9 | pip install \
10 | --user \
11 | --ignore-installed \
12 | 'pylint ~= 2.12.2' \
13 | black \
14 | displayName: Install latest Python lint dependencies
15 |
16 | - script: |
17 | set -e
18 | printf "Installing npm\n"
19 | sudo dnf install -y npm
20 | displayName: Install JavaScript lint dependencies
21 |
--------------------------------------------------------------------------------
/tests/azure/templates/publish-build.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | artifactName: ''
3 | targetPath: ''
4 | displayName: ''
5 |
6 | steps:
7 | - task: PublishPipelineArtifact@1
8 | inputs:
9 | artifactName: ${{ parameters.artifactName }}
10 | targetPath: ${{ parameters.targetPath }}
11 | displayName: ${{ parameters.displayName }}
12 |
--------------------------------------------------------------------------------
/tests/azure/templates/variables-common.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | VM_IMAGE: 'Ubuntu-18.04'
3 |
--------------------------------------------------------------------------------
/tests/azure/templates/variables-fedora.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | FC_PLATFORM: fedora
3 | # the Docker public image to build FC packages (rpms)
4 | DOCKER_BUILD_IMAGE: 'fedora:34'
5 |
6 | # the template to install FC buildtime dependencies
7 | PREPARE_BUILD_TEMPLATE: ${{ format('prepare-build-{0}.yml', variables.FC_PLATFORM) }}
8 |
9 | # the template to configure project (rpms)
10 | CONFIGURE_TEMPLATE: ${{ format('configure-{0}.yml', variables.FC_PLATFORM) }}
11 |
12 | # the template to build FC packages (rpms)
13 | BUILD_TEMPLATE: ${{ format('build-{0}.yml', variables.FC_PLATFORM) }}
14 |
15 | # the template to install latest Pylint
16 | PREPARE_LINT_TEMPLATE: ${{ format('prepare-lint-{0}.yml', variables.FC_PLATFORM) }}
17 |
--------------------------------------------------------------------------------
/tests/azure/templates/variables.yml:
--------------------------------------------------------------------------------
1 | variables-fedora.yml
--------------------------------------------------------------------------------
/tests/data/fc_goa_providers_test.ini:
--------------------------------------------------------------------------------
1 | [Provider provider]
2 | MailEnabled=true
3 | DocumentsEnabled=true
4 |
5 | [Provider pizza_provider]
6 | ProviderName=My Pizza Provider
7 | HotdogEnabled=false
8 | PizzaEnabled=true
9 | PepperoniEnabled=true
10 |
11 | [Provider special_provider]
12 | Enabled=true
13 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-direct-debug.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-direct-plain-debug.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-direct-plain.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-direct.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-html5-debug.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-modified-html5.xml:
--------------------------------------------------------------------------------
1 |
2 | fc-%(name-uuid)s
3 | %(uuid)s
4 | Fedora - Fleet Commander temporary session
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-nospice.xml:
--------------------------------------------------------------------------------
1 |
2 | fedora-unspiced
3 | 0999a0ee-a4c4-11e5-b3a5-68f728db19d3
4 | Fedora unspiced
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/tests/data/libvirt_domain-orig.xml:
--------------------------------------------------------------------------------
1 |
2 | fedora-unkno
3 | e2e3ad2a-7c2d-45d9-b7bc-fefb33925a81
4 | Fedora
5 |
6 |
7 | installed
8 | http://fedoraproject.org/fedora/unknown
9 | http://fedoraproject.org/fedora/unknown:3
10 | /home/user/Downloads/Fedora-Live-Workstation-x86_64-23-10.iso
11 |
12 |
13 | 2097152
14 | 2097152
15 | 4
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Broadwell
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | destroy
34 | restart
35 | destroy
36 |
37 |
38 |
39 |
40 |
41 | /usr/bin/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/tests/data/test.gschema.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
10 | true
11 | Test
12 | A test boolean property
13 |
14 |
15 |
16 |
17 |
18 |
19 | true
20 | Test
21 | A test boolean property
22 |
23 |
24 | true
25 | Test
26 | A test boolean property
27 |
28 |
29 |
30 |
31 |
32 |
33 | true
34 | Test
35 | A test boolean property
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/directorymock.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=2 sw=2 sts=2
3 |
4 | # Copyright (C) 2018, 2019 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Oliver Gutiérrez
20 | # Alberto Ruiz
21 |
22 |
23 | import os
24 | import logging
25 | import json
26 |
27 |
28 | class DirectoryData:
29 | def __init__(self, datadir=None):
30 | logging.debug("Directory mock data initialized. Path: %s", datadir)
31 | self.datadir = datadir
32 | # Data storage
33 | self.global_policy = 1
34 | self.profiles = {}
35 |
36 | def get_json(self):
37 | data = {
38 | "policy": self.global_policy,
39 | "profiles": self.profiles,
40 | }
41 | logging.debug("Directory mock data to export: %s", data)
42 | jsondata = json.dumps(data)
43 | logging.debug("Directory mock JSON data to export: %s", jsondata)
44 | return jsondata
45 |
46 | def save_to_datadir(self, filename="directorymock-data.json"):
47 | if self.datadir is not None:
48 | path = os.path.join(self.datadir, filename)
49 | logging.debug("Directory mock exporting data to %s", path)
50 | with open(path, "w", encoding="utf-8") as fd:
51 | fd.write(self.get_json())
52 |
53 | logging.debug("Directory mock data saved to %s", path)
54 | else:
55 | logging.debug("Directory mock not exporting data (No datadir)")
56 |
57 | # Decorator for exporting data to file
58 | @classmethod
59 | def export_data(cls, fun):
60 | def wrapper(self, *args, **kwargs):
61 | result = fun(self, *args, **kwargs)
62 | # Save data storaged in data member
63 | self.data.save_to_datadir()
64 | return result
65 |
66 | return wrapper
67 |
68 |
69 | class DirectoryConnector:
70 | """
71 | Directory connector module mocking class
72 | """
73 |
74 | data = None
75 |
76 | def __init__(self, domain=None):
77 | pass
78 |
79 | def connect(self, sanity_check=True):
80 | """
81 | Connect to AD server
82 | """
83 | logging.debug("Directory Mock: Connection")
84 |
85 | def get_global_policy(self):
86 | return self.data.global_policy
87 |
88 | @DirectoryData.export_data
89 | def set_global_policy(self, policy):
90 | self.data.global_policy = policy
91 |
92 | @DirectoryData.export_data
93 | def save_profile(self, profile):
94 | # Check if profile already exists
95 | cn = profile.get("cn", None)
96 | if cn is not None:
97 | # Modifying existing profile
98 | logging.debug("Directory Mock: Trying to modify profile with cn %s", cn)
99 | if cn in self.data.profiles:
100 | logging.debug("Directory Mock: Modifying existing profile %s", cn)
101 | else:
102 | logging.debug("Directory Mock: Profile %s does not exist. Saving.", cn)
103 | self.data.profiles[cn] = profile
104 | else:
105 | # Saving new profile
106 | cn = profile["name"]
107 | logging.debug(
108 | "Directory Mock: Saving new profile. Using name as new id: %s", cn
109 | )
110 | self.data.profiles[cn] = profile
111 | return cn
112 |
113 | @DirectoryData.export_data
114 | def del_profile(self, cn):
115 | logging.debug("Directory Mock: Deleting profile %s", cn)
116 | if cn in self.data.profiles:
117 | del self.data.profiles[cn]
118 |
119 | def get_profiles(self):
120 | logging.debug("Directory Mock: Getting profile list")
121 | profiles = []
122 | for cn, profile in self.data.profiles.items():
123 | profiles.append((cn, profile["name"], profile["description"]))
124 | return profiles
125 |
126 | def get_profile(self, cn):
127 | logging.debug("Directory Mock: Getting profile %s", cn)
128 | return self.data.profiles.get(cn, {})
129 |
--------------------------------------------------------------------------------
/tests/fcdbusclient.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2015 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | import time
23 | import json
24 | import logging
25 |
26 | import dbus
27 |
28 | logger = logging.getLogger(__name__)
29 |
30 | DBUS_BUS_NAME = "org.freedesktop.FleetCommanderTest"
31 | DBUS_OBJECT_PATH = "/org/freedesktop/FleetCommanderTest"
32 | DBUS_INTERFACE_NAME = "org.freedesktop.FleetCommander"
33 | DBUS_TESTING_INTERFACE_NAME = "org.freedesktop.FleetCommanderTest"
34 |
35 |
36 | class FleetCommanderDbusClient:
37 |
38 | """
39 | Fleet commander dbus client
40 | """
41 |
42 | DEFAULT_BUS = dbus.SessionBus
43 | CONNECTION_TIMEOUT = 1
44 |
45 | def __init__(self, bus=None):
46 | """
47 | Class initialization
48 | """
49 | if bus is None:
50 | bus = self.DEFAULT_BUS()
51 | self.bus = bus
52 |
53 | t = time.time()
54 | while time.time() - t < self.CONNECTION_TIMEOUT:
55 | try:
56 | self.obj = self.bus.get_object(DBUS_BUS_NAME, DBUS_OBJECT_PATH)
57 | self.iface = dbus.Interface(
58 | self.obj, dbus_interface=DBUS_INTERFACE_NAME
59 | )
60 | return
61 | except Exception:
62 | pass
63 | raise Exception("Timed out trying to connect to fleet commander dbus service")
64 |
65 | def get_initial_values(self):
66 | return self.iface.GetInitialValues()
67 |
68 | def do_domain_connection(self):
69 | return self.iface.DoDomainConnection()
70 |
71 | def heartbeat(self):
72 | return self.iface.HeartBeat()
73 |
74 | def check_needs_configuration(self):
75 | return self.iface.CheckNeedsConfiguration()
76 |
77 | def get_public_key(self):
78 | return self.iface.GetPublicKey()
79 |
80 | def check_hypervisor_config(self, data):
81 | return json.loads(self.iface.CheckHypervisorConfig(json.dumps(data)))
82 |
83 | def get_hypervisor_config(self):
84 | return json.loads(self.iface.GetHypervisorConfig())
85 |
86 | def set_hypervisor_config(self, data):
87 | return json.loads(self.iface.SetHypervisorConfig(json.dumps(data)))
88 |
89 | def check_known_host(self, host):
90 | return json.loads(self.iface.CheckKnownHost(host))
91 |
92 | def add_known_host(self, host):
93 | return json.loads(self.iface.AddKnownHost(host))
94 |
95 | def install_pubkey(self, host, user, passwd):
96 | return json.loads(self.iface.InstallPubkey(host, user, passwd))
97 |
98 | def get_global_policy(self):
99 | return json.loads(self.iface.GetGlobalPolicy())
100 |
101 | def set_global_policy(self, policy):
102 | return json.loads(self.iface.SetGlobalPolicy(policy))
103 |
104 | def save_profile(self, profiledata):
105 | return json.loads(self.iface.SaveProfile(json.dumps(profiledata)))
106 |
107 | def get_profiles(self):
108 | return json.loads(self.iface.GetProfiles())
109 |
110 | def get_profile(self, uid):
111 | return json.loads(self.iface.GetProfile(uid))
112 |
113 | def delete_profile(self, uid):
114 | return json.loads(self.iface.DeleteProfile(uid))
115 |
116 | def list_domains(self):
117 | return json.loads(self.iface.ListDomains())
118 |
119 | def session_start(self, domain_uuid):
120 | return json.loads(self.iface.SessionStart(domain_uuid))
121 |
122 | def session_stop(self):
123 | return json.loads(self.iface.SessionStop())
124 |
125 | def session_save(self, uid, data):
126 | return json.loads(self.iface.SessionSave(uid, json.dumps(data)))
127 |
128 | def is_session_active(self, uuid=""):
129 | return self.iface.IsSessionActive(uuid)
130 |
131 | def get_change_listener_port(self):
132 | return self.iface.GetChangeListenerPort()
133 |
134 | def get_goa_providers(self):
135 | return json.loads(self.iface.GetGOAProviders())
136 |
137 | def quit(self):
138 | return self.iface.Quit()
139 |
--------------------------------------------------------------------------------
/tests/ldapmock.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=2 sw=2 sts=2
3 |
4 | # Copyright (C) 2019 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | # Python imports
23 | import logging
24 |
25 |
26 | DOMAIN_DATA = {}
27 |
28 |
29 | class SASLMock:
30 | @staticmethod
31 | def sasl(cb_value_dict, mech):
32 | # We asume auth is OK as long as mechanism is GSSAPI
33 | # We ignore callbacks
34 | if mech == "GSSAPI":
35 | return "AUTH OK"
36 | raise Exception("SASLMock: Auth mechanism is not GSSAPI (Kerberos)")
37 |
38 |
39 | class LDAPConnectionMock:
40 |
41 | protocol_version = 3
42 |
43 | def __init__(self, server_address):
44 | logging.debug("LDAPMock initializing connection: %s", server_address)
45 | self.server_address = server_address
46 | self.options = {}
47 | self._domain_data = DOMAIN_DATA
48 |
49 | def _ldif_to_ldap_data(self, ldif):
50 | data = {}
51 | for elem in ldif:
52 | data[elem[0]] = (elem[1],)
53 | return data
54 |
55 | def set_option(self, key, value):
56 | self.options[key] = value
57 |
58 | def sasl_interactive_bind_s(self, who, sasl_auth):
59 | # We assume auth is ok if who is '' and sasl_auth was created using sasl
60 | if who == "" and sasl_auth == "AUTH OK":
61 | return
62 | raise Exception(
63 | "SASLMock: Incorrect parameters for SASL binding: %s, %s" % (who, sasl_auth)
64 | )
65 |
66 | def search_s(
67 | self,
68 | base,
69 | scope,
70 | filterstr="(objectClass=*)",
71 | attrlist=None,
72 | attrsonly=0,
73 | timeout=-1,
74 | ):
75 | logging.debug("LDAPMock search_s: %s - %s", base, filterstr)
76 | if base == "DC=FC,DC=AD":
77 | groupfilter = "(&(objectclass=group)(CN="
78 | sidfilter = "(&(|(objectclass=computer)(objectclass=user)(objectclass=group))(objectSid="
79 | if filterstr == "(objectClass=*)" and attrlist == ["objectSid"]:
80 | return (("cn", self._domain_data["domain"]),)
81 | if sidfilter in filterstr:
82 | filtersid = filterstr[len(sidfilter) : -2]
83 | for objclass in ["users", "groups", "hosts"]:
84 | for _key, elem in self._domain_data[objclass].items():
85 | # Use unpacked object sid to avoid use of ndr_unpack
86 | if filtersid == elem["unpackedObjectSid"]:
87 | return [
88 | (elem["cn"], elem),
89 | ]
90 | elif groupfilter in filterstr:
91 | groupname = filterstr[len(groupfilter) : -2]
92 | if groupname in self._domain_data["groups"].keys():
93 | return (("cn", self._domain_data["groups"][groupname]),)
94 | elif base == "CN=Users,DC=FC,DC=AD":
95 | userfilter = "(&(objectclass=user)(CN="
96 | if userfilter in filterstr:
97 | username = filterstr[len(userfilter) : -2]
98 | if username in self._domain_data["users"].keys():
99 | return (("cn", self._domain_data["users"][username]),)
100 | elif base == "CN=Computers,DC=FC,DC=AD":
101 | hostfilter = "(&(objectclass=computer)(CN="
102 | if hostfilter in filterstr:
103 | hostname = filterstr[len(hostfilter) : -2]
104 | if hostname in self._domain_data["hosts"].keys():
105 | return (("cn", self._domain_data["hosts"][hostname]),)
106 | elif base == "CN=Policies,CN=System,DC=FC,DC=AD":
107 | if filterstr == "(objectclass=groupPolicyContainer)":
108 | profile_list = []
109 | for cn, _profile in self._domain_data["profiles"].items():
110 | profile_list.append((cn, self._domain_data["profiles"][cn]))
111 | return profile_list
112 | if "(displayName=" in filterstr:
113 | displayname = filterstr[len("(displayName=") : -1]
114 | # Trying to get a profile by its display name
115 | for _key, elem in self._domain_data["profiles"].items():
116 | if elem["displayName"][0].decode() == displayname:
117 | return [(elem["cn"], elem)]
118 | else:
119 | cn = "CN=%s,CN=Policies,CN=System,DC=FC,DC=AD" % filterstr[4:-1]
120 | if cn in self._domain_data["profiles"].keys():
121 | return [(cn, self._domain_data["profiles"][cn])]
122 | return []
123 |
124 | def add_s(self, dn, ldif):
125 | self._domain_data["profiles"][dn] = self._ldif_to_ldap_data(ldif)
126 |
127 | def modify_s(self, dn, ldif):
128 | profile = self._domain_data["profiles"][dn]
129 | for dif in ldif:
130 | value = (dif[2],)
131 | if dif[1] in ["displayName", "description"]:
132 | value = (dif[2],)
133 | profile[dif[1]] = value
134 |
135 | def delete_s(self, dn):
136 | logging.debug("LDAPMock: delete_s %s", dn)
137 | if dn in self._domain_data["profiles"].keys():
138 | del self._domain_data["profiles"][dn]
139 |
140 |
141 | # Mock sasl module
142 | sasl = SASLMock
143 |
144 |
145 | # Constants
146 | OPT_REFERRALS = 1
147 | SCOPE_SUBTREE = 2
148 | SCOPE_BASE = 3
149 | MOD_REPLACE = 4
150 |
151 |
152 | # Functions
153 | def initialize(server_address):
154 | return LDAPConnectionMock(server_address)
155 |
--------------------------------------------------------------------------------
/tests/python-wrapper.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | exec "$PYTHON" "$@"
--------------------------------------------------------------------------------
/tests/smbmock.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=2 sw=2 sts=2
3 |
4 | # Copyright (C) 2019 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | import os
23 | import shutil
24 | import json
25 | import logging
26 |
27 | # Temporary directory. Set on each test run at setUp()
28 | TEMP_DIR = None
29 |
30 |
31 | class SMBMock:
32 | def __init__(self, servername, service, lp, creds):
33 | logging.debug("SMBMock: Mocking SMB at \\\\%s\\%s", servername, service)
34 | self.tempdir = TEMP_DIR
35 | logging.debug("Using temporary directory at %s", self.tempdir)
36 | self.profilesdir = os.path.join(self.tempdir, "%s/Policies" % servername)
37 | if not os.path.exists(self.profilesdir):
38 | os.makedirs(self.profilesdir)
39 |
40 | def _translate_path(self, uri):
41 | return os.path.join(self.tempdir, uri.replace("\\", "/"))
42 |
43 | def loadfile(self, furi):
44 | logging.debug("SMBMock: LOADFILE %s", furi)
45 | path = self._translate_path(furi)
46 | with open(path, "rb") as fd:
47 | data = fd.read()
48 |
49 | return data
50 |
51 | def savefile(self, furi, data):
52 | logging.debug("SMBMock: SAVEFILE %s", furi)
53 | path = self._translate_path(furi)
54 | with open(path, "wb") as fd:
55 | fd.write(data)
56 |
57 | logging.debug("SMBMock: Written %s", path)
58 |
59 | def chkpath(self, duri):
60 | logging.debug("SMBMock: CHKPATH %s", duri)
61 | path = self._translate_path(duri)
62 | return os.path.exists(path)
63 |
64 | def mkdir(self, duri):
65 | logging.debug("SMBMock: MKDIR %s", duri)
66 | path = self._translate_path(duri)
67 | if not os.path.exists(path):
68 | os.makedirs(path)
69 |
70 | def set_acl(self, duri, fssd, sio):
71 | logging.debug("SMBMock: SETACL %s", duri)
72 | path = self._translate_path(duri)
73 | aclpath = os.path.join(path, "__acldata__.json")
74 | acldata = json.dumps(
75 | {
76 | "uri": duri,
77 | "sio": sio,
78 | "fssd": fssd.as_sddl(),
79 | }
80 | )
81 | with open(aclpath, "w", encoding="utf-8") as fd:
82 | fd.write(acldata)
83 |
84 | def deltree(self, duri):
85 | logging.debug("SMBMock: DELTREE %s", duri)
86 | path = self._translate_path(duri)
87 | if os.path.exists(path):
88 | shutil.rmtree(path)
89 |
--------------------------------------------------------------------------------
/tests/test_database.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python-wrapper.sh
2 | # -*- coding: utf-8 -*-
3 | # vi:ts=2 sw=2 sts=2
4 |
5 | # Copyright (C) 2015 Red Hat, Inc.
6 | #
7 | # This program is free software; you can redistribute it and/or
8 | # modify it under the terms of the GNU Lesser General Public
9 | # License as published by the Free Software Foundation; either
10 | # version 2.1 of the licence, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | # Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public
18 | # License along with this program; if not, see .
19 | #
20 | # Authors: Alberto Ruiz
21 | # Oliver Gutiérrez
22 |
23 | # Python imports
24 | from __future__ import absolute_import
25 | import logging
26 | import json
27 | import os
28 | import unittest
29 |
30 | logger = logging.getLogger(os.path.basename(__file__))
31 |
32 | from fleetcommander.database import DBManager
33 | from fleetcommander.database import SCHEMA_VERSION
34 |
35 |
36 | class UnsupportedType:
37 | """
38 | Unsupported type for testing
39 | """
40 |
41 |
42 | class TestDBManager(unittest.TestCase):
43 |
44 | test_setting = {"key": "/foo/bar", "schema": "org.gnome.testkey", "value": False}
45 |
46 | test_setting_json = json.dumps(test_setting)
47 |
48 | INITIAL_VALUES = {
49 | "testkeystr": "strvalue",
50 | "testkeybytes": b"bytesvalue",
51 | "testkeyint": 42,
52 | "testkeyfloat": 42.0,
53 | "testkeytuple": ("foo", 42, "bar"),
54 | "testkeylist": ["foo", 42, "bar"],
55 | "testkeydict": test_setting,
56 | }
57 |
58 | def setUp(self):
59 | # Initialize memory database
60 | self.db = DBManager("file:mem_initial?mode=memory&cache=shared")
61 | # Add values to config
62 | for k, v in self.INITIAL_VALUES.items():
63 | self.db.config[k] = v
64 |
65 | def test_01_config_dictionary_iteration(self):
66 | """Assumes config contains only INITIAL_VALUES."""
67 | items = list(self.db.config.items())
68 | self.assertEqual(len(items), 7)
69 | for item in items:
70 | self.assertEqual(item[1], self.INITIAL_VALUES[item[0]])
71 |
72 | def test_02_config_dictionary_setitem(self):
73 | # Add unsupported type to config
74 | self.assertRaises(
75 | ValueError, self.db.config.__setitem__, "unsupported", UnsupportedType()
76 | )
77 |
78 | def test_03_config_dictionary_getitem(self):
79 | # Get inexistent value
80 | self.assertRaises(KeyError, self.db.config.__getitem__, "unknownkey")
81 | # Get existent values
82 | for k, v in self.INITIAL_VALUES.items():
83 | self.assertEqual(self.db.config[k], v)
84 | # Get default values
85 | self.assertEqual(self.db.config.get("testkeystr", "defaultvalue"), "strvalue")
86 | self.assertEqual(
87 | self.db.config.get("unknownkey", "defaultvalue"), "defaultvalue"
88 | )
89 |
90 | def test_04_config_dictionary_itemmembership(self):
91 | # Set data in config
92 | self.assertTrue("testkeystr" in self.db.config)
93 | self.assertFalse("unknownkey" in self.db.config)
94 |
95 | def test_05_config_dictionary_deleteitem(self):
96 | # Delete values from config
97 | self.assertTrue("testkeystr" in self.db.config)
98 | del self.db.config["testkeystr"]
99 | self.assertFalse("testkeystr" in self.db.config)
100 |
101 | def test_06_config_dictionary_setdefault(self):
102 | value = self.db.config.setdefault("testkeystr", "anotherstrvalue")
103 | self.assertEqual(self.db.config["testkeystr"], "strvalue")
104 | self.assertEqual(value, "strvalue")
105 | value = self.db.config.setdefault("anothertestkeystr", "anotherstrvalue")
106 | self.assertEqual(self.db.config["anothertestkeystr"], "anotherstrvalue")
107 | self.assertEqual(value, "anotherstrvalue")
108 |
109 | def test_07_update_schema(self):
110 | """Test an upgrade of sqlite db schema."""
111 | tables = ["config", "profiles"]
112 | upgrade_db = "file:mem_upgrade?mode=memory&cache=shared"
113 | old_db = DBManager(upgrade_db)
114 | old_schema_version = 1
115 | self.assertLess(old_schema_version, SCHEMA_VERSION)
116 |
117 | # downgrade SCHEMA_VERSION
118 | for table in tables:
119 | getattr(old_db, table)["SCHEMA_VERSION"] = old_schema_version
120 |
121 | # reinitialize DBManager to trigger schema upgrade
122 | new_db = DBManager(upgrade_db)
123 | for table in tables:
124 | self.assertEqual(getattr(new_db, table)["SCHEMA_VERSION"], SCHEMA_VERSION)
125 |
126 |
127 | if __name__ == "__main__":
128 | logging.basicConfig(level=logging.DEBUG)
129 | unittest.main(verbosity=2)
130 |
--------------------------------------------------------------------------------
/tests/test_fcdbus.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2015 Red Hat, Inc.
4 | #
5 | # GNOME Maps is free software; you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by the
7 | # Free Software Foundation; either version 2 of the License, or (at your
8 | # option) any later version.
9 | #
10 | # GNOME Maps is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 | # for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License along
16 | # with GNOME Maps; if not, write to the Free Software Foundation,
17 | # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutierrez
21 |
22 | # We assume dbus-launch never fails
23 |
24 | kill $DBUS_SESSION_BUS_PID > /dev/null 2> /dev/null
25 |
26 | eval `dbus-launch`
27 | export DBUS_SESSION_BUS_ADDRESS
28 |
29 |
30 | $PYTHON $TOPSRCDIR/tests/_mock_realmd_dbus.py &
31 | DBUS_MOCK_PID=$!
32 |
33 | $PYTHON $TOPSRCDIR/tests/_wait_for_name.py org.freedesktop.realmd
34 | if [ $? -ne 0 ] ; then
35 | echo "Failed to acquire bus name org.freedesktop.realmd"
36 | exit 1
37 | fi
38 |
39 | ps -p $DBUS_MOCK_PID > /dev/null 2> /dev/null
40 | if [ $? -ne 0 ] ; then
41 | echo "Failed to launch _mock_realmd_dbus.py"
42 | exit 1
43 | fi
44 |
45 | # Execute fleet commander dbus service tests
46 | $PYTHON $TOPSRCDIR/tests/_fcdbus_tests.py
47 | RET=$?
48 |
49 | kill $DBUS_SESSION_BUS_PID
50 |
51 | rm $TOPSRCDIR/_build/sub/admin/fleetcommander/constants.pyc > /dev/null 2>&1
52 |
53 | exit $RET
54 |
--------------------------------------------------------------------------------
/tests/test_fcdbus_service.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=4 sw=4 sts=4
3 |
4 | # Copyright (C) 2015 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Authors: Alberto Ruiz
20 | # Oliver Gutiérrez
21 |
22 | # Python imports
23 | from __future__ import absolute_import
24 |
25 | from collections import namedtuple
26 |
27 | import os
28 | import sys
29 | import logging
30 |
31 | from gi.repository import Gio
32 |
33 | # Fleet commander imports
34 | from fleetcommander import libvirtcontroller
35 | from fleetcommander import sshcontroller
36 | from fleetcommander import fcdbus
37 |
38 | # Mock directory system
39 | from tests import directorymock
40 |
41 | logger = logging.getLogger(os.path.basename(__file__))
42 |
43 | fcdbus.fcfreeipa.FreeIPAConnector = directorymock.DirectoryConnector
44 | fcdbus.fcad.ADConnector = directorymock.DirectoryConnector
45 |
46 | # Change bus names
47 | fcdbus.DBUS_BUS_NAME = "org.freedesktop.FleetCommanderTest"
48 | fcdbus.DBUS_OBJECT_PATH = "/org/freedesktop/FleetCommanderTest"
49 |
50 |
51 | # Mock libvirt controller
52 | def controller(viewer_type, data_path, username, hostname, mode):
53 | return MockLibVirtController(data_path, username, hostname, mode)
54 |
55 |
56 | fcdbus.libvirtcontroller.controller = controller
57 |
58 |
59 | class MockLibVirtController(libvirtcontroller.LibVirtTunnelSpice):
60 |
61 | TEMPLATE_UUID = "e2e3ad2a-7c2d-45d9-b7bc-fefb33925a81"
62 | SESSION_UUID = "fefb45d9-5a81-3392-b7bc-e2e37c2d"
63 |
64 | DOMAINS_LIST = [
65 | {
66 | "uuid": TEMPLATE_UUID,
67 | "name": "fedora-unkno",
68 | "active": False,
69 | "temporary": False,
70 | }
71 | ]
72 |
73 | def __init__(self, data_path, username, hostname, mode):
74 |
75 | self.data_dir = os.path.abspath(data_path)
76 | if not os.path.exists(self.data_dir):
77 | os.makedirs(self.data_dir)
78 |
79 | self.public_key_file = os.path.join(self.data_dir, "id_rsa.pub")
80 |
81 | with open(self.public_key_file, "w", encoding="utf-8") as fd:
82 | fd.write("PUBLIC_KEY")
83 |
84 | self.session_params = namedtuple(
85 | "session_params",
86 | [
87 | "domain",
88 | "details",
89 | ],
90 | )
91 |
92 | def list_domains(self):
93 | return self.DOMAINS_LIST
94 |
95 | def session_start(self, identifier, debug_logger=False):
96 | """Return abstract session cookie."""
97 | self.DOMAINS_LIST.append(
98 | {
99 | "uuid": self.SESSION_UUID,
100 | "name": "fc-",
101 | "active": True,
102 | "temporary": True,
103 | }
104 | )
105 | details = {
106 | "host": "localhost",
107 | "viewer": "spice_html5",
108 | "ticket": "spice_ticket",
109 | }
110 |
111 | return self.session_params(
112 | domain=self.SESSION_UUID,
113 | details=details,
114 | )
115 |
116 | def session_stop(self, identifier):
117 | for d in self.DOMAINS_LIST:
118 | if d["uuid"] == identifier:
119 | self.DOMAINS_LIST.remove(d)
120 |
121 |
122 | class TestFleetCommanderDbusService(fcdbus.FleetCommanderDbusService):
123 | def __init__(self, test_directory):
124 |
125 | args = {
126 | "log_level": "debug",
127 | "debug_protocol": False,
128 | "log_format": "\n[%(levelname)s] %(asctime)-15s %(message)s",
129 | "debug_logger": False,
130 | "data_dir": test_directory,
131 | "tmp_session_destroy_timeout": 60,
132 | "auto_quit_timeout": 60,
133 | "default_profile_priority": 50,
134 | # Force state directory
135 | "state_dir": test_directory,
136 | }
137 |
138 | directorymock.DirectoryConnector.data = directorymock.DirectoryData(
139 | test_directory
140 | )
141 |
142 | self.REALMD_BUS = Gio.BusType.SESSION
143 |
144 | super().__init__(args)
145 |
146 | self.known_hosts_file = os.path.join(test_directory, "known_hosts")
147 |
148 | self.GOA_PROVIDERS_FILE = os.path.join(
149 | os.environ["TOPSRCDIR"], "tests/data/fc_goa_providers_test.ini"
150 | )
151 |
152 | self.ssh.install_pubkey = self.ssh_install_pubkey_mock
153 |
154 | def ssh_install_pubkey_mock(self, pubkey, user, password, host, port):
155 | """
156 | Just mock ssh command execution
157 | """
158 | if password != "password":
159 | raise sshcontroller.SSHControllerException("Invalid credentials")
160 |
161 |
162 | if __name__ == "__main__":
163 | logging.basicConfig(level=logging.DEBUG)
164 | TestFleetCommanderDbusService(sys.argv[1]).run()
165 |
--------------------------------------------------------------------------------
/tests/test_logger_connmgr.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python-wrapper.sh
2 | # -*- coding: utf-8 -*-
3 | # vi:ts=2 sw=2 sts=2
4 |
5 | # Copyright (C) 2015 Red Hat, Inc.
6 | #
7 | # This program is free software; you can redistribute it and/or
8 | # modify it under the terms of the GNU Lesser General Public
9 | # License as published by the Free Software Foundation; either
10 | # version 2.1 of the licence, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | # Lesser General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Lesser General Public
18 | # License along with this program; if not, see .
19 | #
20 | # Authors: Alberto Ruiz
21 | # Oliver Gutiérrez
22 |
23 | # Python imports
24 | from __future__ import absolute_import
25 | from __future__ import division
26 | from __future__ import print_function
27 |
28 | import json
29 | import logging
30 | import math
31 | import os
32 | import re
33 | import unittest
34 |
35 | from unittest.mock import mock_open, patch
36 |
37 | # GObject Introspection imports
38 | from gi.repository import Gio
39 |
40 | from fleet_commander_logger import (
41 | FC_LOGGER_PROTO_CHUNK_SIZE,
42 | FC_LOGGER_PROTO_HEADER,
43 | FC_LOGGER_PROTO_SUFFIX,
44 | )
45 | import fleet_commander_logger as FleetCommander
46 |
47 | logger = logging.getLogger(os.path.basename(__file__))
48 |
49 |
50 | def read_file(filename):
51 | with open(filename, encoding="utf-8") as fd:
52 | return fd.read()
53 |
54 |
55 | def parse_fc_message(msg):
56 | """Parser for completely received message of FleetCommander Logger.
57 |
58 | Return list of JSON objects.
59 | """
60 | m = re.match(rf"^{FC_LOGGER_PROTO_HEADER}(.*){FC_LOGGER_PROTO_SUFFIX}$", msg)
61 | return m.group(1).split(FC_LOGGER_PROTO_SUFFIX)
62 |
63 |
64 | class TestConnMgr(unittest.TestCase):
65 | """Test SpicePortManager."""
66 |
67 | def test_01_proto_version(self):
68 | """Test SpicePortManager sends logger protocol version on instantiation."""
69 | TMPFILE = Gio.file_new_tmp("fc_logger_spiceport_XXXXXX")
70 | path = TMPFILE[0].get_path()
71 | FleetCommander.SpicePortManager(path)
72 |
73 | # Check PROTO header has been written to spiceport file
74 | raw_data = read_file(path)
75 | self.assertEqual(raw_data, FC_LOGGER_PROTO_HEADER)
76 |
77 | def test_02_submit_change(self):
78 | # Get temporary file
79 | TMPFILE = Gio.file_new_tmp("fc_logger_spiceport_XXXXXX")
80 | path = TMPFILE[0].get_path()
81 | mgr = FleetCommander.SpicePortManager(path)
82 | PAYLOAD = '["PAYLOAD"]'
83 | expected_data = ['{"ns": "org.gnome.gsettings", "data": "[\\"PAYLOAD\\"]"}']
84 | mgr.submit_change("org.gnome.gsettings", PAYLOAD)
85 |
86 | # Check change is in queue
87 | self.assertEqual(len(mgr.queue), 1)
88 | self.assertEqual(mgr.queue[0]["ns"], "org.gnome.gsettings")
89 | self.assertEqual(mgr.queue[0]["data"], PAYLOAD)
90 |
91 | # Clean queue and quit
92 | mgr.give_up()
93 | self.assertEqual(len(mgr.queue), 0)
94 | self.assertEqual(mgr.timeout, 0)
95 |
96 | # Check data has been written to spiceport file
97 | raw_data = read_file(path)
98 | actual = parse_fc_message(raw_data)
99 | self.assertListEqual(actual, expected_data)
100 | # check that the change is correct dumped JSON object
101 | # dump it again for string comparison
102 | self.assertEqual(
103 | json.dumps(json.loads(actual[0])), json.dumps(json.loads(expected_data[0]))
104 | )
105 |
106 | def test_03_manager_queue(self):
107 | # Get temporary file
108 | TMPFILE = Gio.file_new_tmp("fc_logger_spiceport_XXXXXX")
109 | path = TMPFILE[0].get_path()
110 |
111 | mgr = FleetCommander.SpicePortManager(path)
112 | PAYLOADS = ["1", "2", "3", "4", "5"]
113 | expected_data = []
114 |
115 | for pl in PAYLOADS:
116 | mgr.submit_change("org.gnome.gsettings", pl)
117 | expected_data.append(json.dumps({"ns": "org.gnome.gsettings", "data": pl}))
118 |
119 | self.assertEqual(len(PAYLOADS), len(mgr.queue))
120 |
121 | index = 0
122 | for elem in mgr.queue:
123 | self.assertEqual(elem["ns"], "org.gnome.gsettings")
124 | self.assertEqual(elem["data"], PAYLOADS[index])
125 | index += 1
126 |
127 | # Clean queue and quit
128 | mgr.give_up()
129 | self.assertEqual(len(mgr.queue), 0)
130 | self.assertEqual(mgr.timeout, 0)
131 |
132 | # Check data has been written to spiceport file
133 | raw_data = read_file(path)
134 | actual = parse_fc_message(raw_data)
135 | self.assertListEqual(actual, expected_data)
136 |
137 | def test_04_big_message(self):
138 | """Test logger sends a data in chunks."""
139 | path = "/logger_notify_channel"
140 | payload = "A" * 32768
141 |
142 | with patch("builtins.open", mock_open(), create=True) as m:
143 | mgr = FleetCommander.SpicePortManager(path)
144 |
145 | m.assert_called_once_with(path, "wb", 0)
146 | fd = m()
147 | fd.write.assert_called_once_with(FC_LOGGER_PROTO_HEADER.encode())
148 | fd.write.reset_mock()
149 |
150 | mgr.submit_change("org.gnome.gsettings", payload)
151 |
152 | # Check change is in queue
153 | self.assertEqual(len(mgr.queue), 1)
154 | self.assertEqual(mgr.queue[0]["ns"], "org.gnome.gsettings")
155 | self.assertEqual(mgr.queue[0]["data"], payload)
156 |
157 | # Clean queue and quit
158 | mgr.give_up()
159 | self.assertEqual(len(mgr.queue), 0)
160 | self.assertEqual(mgr.timeout, 0)
161 |
162 | # Check data has been written to the mocked file
163 | expected_data = (
164 | json.dumps({"ns": "org.gnome.gsettings", "data": payload})
165 | + FC_LOGGER_PROTO_SUFFIX
166 | ).encode()
167 |
168 | expected_chunks_count = math.ceil(
169 | len(expected_data) / FC_LOGGER_PROTO_CHUNK_SIZE
170 | )
171 | self.assertEqual(fd.write.call_count, expected_chunks_count)
172 |
173 | actual_data = b""
174 | for call_args in fd.write.call_args_list:
175 | write_args, _ = call_args
176 | self.assertEqual(len(write_args), 1)
177 | actual_data += write_args[0]
178 |
179 | self.assertEqual(actual_data, expected_data)
180 |
181 |
182 | if __name__ == "__main__":
183 | logging.basicConfig(level=logging.DEBUG)
184 | unittest.main(verbosity=2)
185 |
--------------------------------------------------------------------------------
/tests/test_logger_dconf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2015 Red Hat, Inc.
4 | #
5 | # GNOME Maps is free software; you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by the
7 | # Free Software Foundation; either version 2 of the License, or (at your
8 | # option) any later version.
9 | #
10 | # GNOME Maps is distributed in the hope that it will be useful, but
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 | # for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License along
16 | # with GNOME Maps; if not, write to the Free Software Foundation,
17 | # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 | #
19 | # Authors: Alberto Ruiz
20 |
21 | if [ "x$TOPSRCDIR" = "x" ] ; then
22 | TOPSRCDIR=`pwd`/../
23 | fi
24 |
25 | # We assume dbus-launch never fails
26 | eval `dbus-launch`
27 | export DBUS_SESSION_BUS_ADDRESS
28 |
29 | dconf write /org/libreoffice/registry/somepath/somekey 123
30 |
31 | export FC_TESTING=true
32 | export GSETTINGS_SCHEMA_DIR=`mktemp -d`
33 |
34 | cp $TOPSRCDIR/tests/data/test.gschema.xml $GSETTINGS_SCHEMA_DIR
35 | if [ $? -ne 0 ] ; then
36 | echo "Failed to copy schema file to tempdir" >&2
37 | exit 1
38 | fi
39 |
40 | glib-compile-schemas $GSETTINGS_SCHEMA_DIR
41 | if [ $? -ne 0 ] ; then
42 | echo "Failed to copy schema file to tempdir" >&2
43 | exit 1
44 | fi
45 |
46 | RET=1
47 |
48 | # We assume dbus-launch never fails
49 | kill $DBUS_SESSION_BUS_PID
50 | eval `dbus-launch`
51 | export DBUS_SESSION_BUS_ADDRESS
52 |
53 | $PYTHON $TOPSRCDIR/tests/_mock_dbus.py > /dev/null 2> /dev/null &
54 | DBUS_MOCK_PID=$!
55 |
56 | $PYTHON $TOPSRCDIR/tests/_wait_for_name.py org.freedesktop.ScreenSaver
57 | if [ $? -ne 0 ] ; then
58 | echo "Failed to acquire bus name org.freedesktop.ScreenSaver"
59 | exit 1
60 | fi
61 |
62 | ps -p $DBUS_MOCK_PID > /dev/null 2> /dev/null
63 | if [ $? -ne 0 ] ; then
64 | echo "Failed to launch _mock_dbus.py" >&2
65 | exit 1
66 | fi
67 |
68 | $PYTHON $TOPSRCDIR/tests/_logger_test_suite.py
69 | RET=$?
70 |
71 | rm -rf $GSETTINGS_SCHEMA_DIR
72 | kill $DBUS_MOCK_PID
73 | kill $DBUS_SESSION_BUS_PID
74 | exit $RET
75 |
--------------------------------------------------------------------------------
/tests/test_logger_main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python-wrapper.sh
2 |
3 | #
4 | # Copyright (C) 2022 FleetCommander Contributors see COPYING for license
5 | #
6 |
7 | from contextlib import redirect_stdout, redirect_stderr
8 | from io import StringIO
9 | from pathlib import Path
10 | from unittest.mock import patch, mock_open
11 | import logging
12 | import unittest
13 |
14 | from fleet_commander_logger import DEFAULT_SPICE_CHANNEL_DEV as spice_device
15 | from fleet_commander_logger import LOG_DEVICE as log_device
16 | import fleet_commander_logger as fc_logger
17 |
18 | logger = logging.getLogger(Path(__file__).name)
19 |
20 |
21 | def device_exists_side_effect(exists_dict):
22 | def _exists(path):
23 | return exists_dict[path]
24 |
25 | return _exists
26 |
27 |
28 | class TestLoggerMain(unittest.TestCase):
29 | def setUp(self):
30 | # writing to nonexistent log device
31 | self.open_patcher = patch.object(fc_logger, "open", mock_open())
32 | self.mock_open = self.open_patcher.start()
33 |
34 | self.device_exists_patcher = patch("fleet_commander_logger.device_exists")
35 | self.mock_exists = self.device_exists_patcher.start()
36 |
37 | self.fclogger_patcher = patch("fleet_commander_logger.FleetCommanderLogger")
38 | self.mock_fclogger = self.fclogger_patcher.start()
39 |
40 | self.basicConfig_patcher = patch.object(fc_logger.logging, "basicConfig")
41 | self.mock_basicConfig = self.basicConfig_patcher.start()
42 |
43 | def tearDown(self):
44 | self.basicConfig_patcher.stop()
45 | self.fclogger_patcher.stop()
46 | self.device_exists_patcher.stop()
47 | self.open_patcher.stop()
48 |
49 | def test_help(self):
50 | """Check help message"""
51 | out = StringIO()
52 | err = StringIO()
53 | with self.assertRaises(SystemExit) as cm, redirect_stdout(out), redirect_stderr(
54 | err
55 | ):
56 | fc_logger.main(["--help"])
57 |
58 | self.assertEqual(cm.exception.code, 0)
59 | self.assertIn(f"usage: {Path(fc_logger.__file__).name} ", out.getvalue())
60 | self.assertEqual(err.getvalue(), "")
61 |
62 | def assert_called_with_handlers(self, *expected_handlers):
63 | # assert_called_once_with doesn't help here due to complexity of objects
64 | # checking manually
65 | self.mock_basicConfig.assert_called_once()
66 | # args
67 | self.assertEqual(self.mock_basicConfig.call_args.args, ())
68 | # kwargs
69 | kwargs = self.mock_basicConfig.call_args.kwargs
70 | self.assertEqual(len(kwargs), 2, msg=f"basicConfig was called with: {kwargs}")
71 | ## handlers
72 | actual_handlers = kwargs["handlers"]
73 | self.assertEqual(len(actual_handlers), len(expected_handlers))
74 | for expected_handler, actual_handler in zip(expected_handlers, actual_handlers):
75 | expected_type, expected_level = expected_handler
76 | self.assertIsInstance(actual_handler, expected_type)
77 | self.assertEqual(
78 | actual_handler.level,
79 | expected_level,
80 | msg=f"Logging level differs for handler: {actual_handler}",
81 | )
82 |
83 | ## root logger level
84 | self.assertEqual(kwargs["level"], logging.DEBUG)
85 |
86 | def test_verbose_logging_existent_log_device(self):
87 | """Check logging in verbose mode if log device exists"""
88 | self.mock_exists.side_effect = device_exists_side_effect(
89 | {spice_device: True, log_device: True}
90 | )
91 | aliases = ["-v", "--verbose", "-d", "--debug"]
92 |
93 | for alias in aliases:
94 | fc_logger.main([alias])
95 | self.assert_called_with_handlers(
96 | (fc_logger.LoggerStreamHandler, logging.DEBUG),
97 | (logging.StreamHandler, logging.DEBUG),
98 | )
99 | # reset calls
100 | self.mock_basicConfig.reset_mock()
101 |
102 | def test_verbose_logging_nonexistent_log_device(self):
103 | """Check logging in verbose mode if log device doesn't exist"""
104 | self.mock_exists.side_effect = device_exists_side_effect(
105 | {spice_device: True, log_device: False}
106 | )
107 | aliases = ["-v", "--verbose", "-d", "--debug"]
108 |
109 | for alias in aliases:
110 | fc_logger.main([alias])
111 | self.assert_called_with_handlers((logging.StreamHandler, logging.DEBUG))
112 | # reset calls
113 | self.mock_basicConfig.reset_mock()
114 |
115 | def test_nonverbose_logging_nonexistent_log_device(self):
116 | """Check logging in non verbose mode if log device doesn't exist"""
117 | self.mock_exists.side_effect = device_exists_side_effect(
118 | {spice_device: True, log_device: False}
119 | )
120 | fc_logger.main([])
121 | self.assert_called_with_handlers((logging.StreamHandler, logging.WARNING))
122 |
123 | def test_nonverbose_logging_existent_log_device(self):
124 | """Check logging in non verbose mode if log device exists"""
125 | self.mock_exists.side_effect = device_exists_side_effect(
126 | {spice_device: True, log_device: True}
127 | )
128 | fc_logger.main([])
129 | self.assert_called_with_handlers(
130 | (fc_logger.LoggerStreamHandler, logging.DEBUG),
131 | (logging.StreamHandler, logging.WARNING),
132 | )
133 |
134 | def test_no_devfile(self):
135 | """Check --no-devfile"""
136 | self.mock_exists.side_effect = device_exists_side_effect(
137 | {spice_device: False, log_device: False}
138 | )
139 | fc_logger.main(["--no-devfile"])
140 | self.mock_fclogger.assert_called_once_with(use_device_file=False)
141 |
142 | def test_missing_spice_device(self):
143 | """Check missing spice device"""
144 | self.mock_exists.side_effect = device_exists_side_effect(
145 | {spice_device: False, log_device: False}
146 | )
147 | with self.assertRaises(SystemExit) as cm, self.assertLogs(
148 | fc_logger.logger, level="ERROR"
149 | ) as lcm:
150 | fc_logger.main([])
151 |
152 | self.assertEqual(cm.exception.code, 1)
153 | self.assertIn("Neither --no-devfile was specified nor device", lcm.output[0])
154 | self.mock_fclogger.assert_not_called()
155 |
156 | def test_spice_device(self):
157 | """Check default usage"""
158 | self.mock_exists.side_effect = device_exists_side_effect(
159 | {spice_device: True, log_device: False}
160 | )
161 | fc_logger.main([])
162 | self.mock_fclogger.assert_called_once_with(use_device_file=True)
163 |
164 |
165 | if __name__ == "__main__":
166 | logging.basicConfig(level=logging.DEBUG)
167 | unittest.main(verbosity=2)
168 |
--------------------------------------------------------------------------------
/tests/test_logger_nm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # We assume dbus-launch never fails
4 |
5 | kill $DBUS_SESSION_BUS_PID > /dev/null 2> /dev/null
6 |
7 | eval `dbus-launch`
8 | export DBUS_SESSION_BUS_ADDRESS
9 |
10 |
11 | $PYTHON $TOPSRCDIR/tests/_mock_nm_dbus.py &
12 | DBUS_MOCK_PID=$!
13 |
14 | $PYTHON $TOPSRCDIR/tests/_wait_for_name.py org.freedesktop.NetworkManager
15 | if [ $? -ne 0 ] ; then
16 | echo "Failed to acquire bus name org.freedesktop.NetworkManager"
17 | exit 1
18 | fi
19 |
20 | ps -p $DBUS_MOCK_PID > /dev/null 2>&1
21 | if [ $? -ne 0 ] ; then
22 | echo "Failed to launch _mock_nm_dbus.py"
23 | exit 1
24 | fi
25 |
26 | # Execute fleet commander NM logger tests
27 | $PYTHON $TOPSRCDIR/tests/_logger_nm.py
28 | RET=$?
29 |
30 | kill $DBUS_SESSION_BUS_PID
31 |
32 | rm $TOPSRCDIR/_build/sub/admin/fleetcommander/constants.pyc > /dev/null 2>&1
33 |
34 | exit $RET
35 |
--------------------------------------------------------------------------------
/tests/tools/ssh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "$@" > $FC_TEST_DIRECTORY/ssh-parms
4 | sync
5 |
6 | function out {
7 | echo $1
8 | exit 0
9 | }
10 |
11 | case "$@" in
12 | *' -N -f' | *' -O exit' )
13 | # open/close ssh tunnel
14 | exit 0
15 | ;;
16 | *'libvirtd '*'echo'* )
17 | out "/run/user/1000/libvirt/libvirt-sock"
18 | ;;
19 | *'qemu-kvm'* )
20 | if [ $FC_TEST_USE_QXL = "1" ]; then
21 | out "qxl"
22 | else
23 | out "virtio"
24 | fi
25 | ;;
26 | *'echo "$XDG_RUNTIME_DIR"' )
27 | # _get_user_runtime_dir
28 | out "/run/user/1001"
29 | ;;
30 | *'openssl x509 -in '* )
31 | # _get_spice_ca_cert
32 | out "FAKE_CA_CERT"
33 | ;;
34 | *'openssl x509 -noout -subject'* )
35 | # _get_spice_cert_subject
36 | out "CN=localhost"
37 | ;;
38 | *) ;;
39 | esac
40 |
41 | exit 0
42 |
--------------------------------------------------------------------------------
/tests/tools/ssh-keygen:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo $@ > $FC_TEST_DIRECTORY/ssh-keygen-parms
3 |
4 | if [ $1 = '-l' ]; then
5 | echo "2048 SHA256:HASH localhost (RSA)"
6 | fi
7 |
--------------------------------------------------------------------------------
/tests/tools/ssh-keyscan:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo $@ > $FC_TEST_DIRECTORY/ssh-keyscan-parms
3 | echo "$3 ssh-rsa KEY"
4 |
--------------------------------------------------------------------------------
/tests/tools/ssh-session-mock:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | read -p 'password: ' -s pass
3 | while [ $pass != 'password' ]
4 | do
5 | echo ''
6 | read -p 'password: ' -s pass
7 | done
8 |
9 | echo ''
10 | read -p '$ ' comm
11 | while [ "$comm" != 'exit' ]
12 | do
13 | read -p '$ ' comm
14 | done
15 |
--------------------------------------------------------------------------------
/tools/chrome-prefs-extract.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # vi:ts=2 sw=2 sts=2
3 |
4 | # Copyright (C) 2015 Red Hat, Inc.
5 | #
6 | # This program is free software; you can redistribute it and/or
7 | # modify it under the terms of the GNU Lesser General Public
8 | # License as published by the Free Software Foundation; either
9 | # version 2.1 of the licence, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | # Lesser General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public
17 | # License along with this program; if not, see .
18 | #
19 | # Author: Oliver Gutiérrez
20 |
21 | # This script is intended to generate a json data file with a mapping between
22 | # preferences and policies so we can use them into logger.
23 | # Source data is got from:
24 | # https://cs.chromium.org/chromium/src/chrome/test/data/policy/policy_test_cases.json
25 |
26 | from __future__ import absolute_import
27 | import sys
28 | import json
29 |
30 | with open(sys.argv[1], "r", encoding="utf-8") as f:
31 | data = json.loads(f.read())
32 |
33 | outdata = {}
34 | for key, value in data.items():
35 | if "pref_mappings" in value:
36 | if value["pref_mappings"] and "pref" in value["pref_mappings"][0]:
37 | outdata[value["pref_mappings"][0]["pref"]] = key
38 |
39 | with open(sys.argv[2], "wb") as f:
40 | f.write(json.dumps(outdata))
41 |
--------------------------------------------------------------------------------
/tools/introspect_goa_providers.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Red Hat, Inc.
3 | *
4 | * This library is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU Lesser General Public
6 | * License as published by the Free Software Foundation; either
7 | * version 2 of the License, or (at your option) any later version.
8 | *
9 | * This library is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | * Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General
15 | * Public License along with this library; if not, see .
16 | */
17 |
18 | #include
19 |
20 | #include
21 |
22 | #define GOA_API_IS_SUBJECT_TO_CHANGE
23 | #define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
24 | #include
25 |
26 | static struct
27 | {
28 | GoaProviderFeatures feature;
29 | const gchar *key;
30 | } provider_features_info[] = {
31 | {
32 | .feature = GOA_PROVIDER_FEATURE_MAIL,
33 | .key = "MailEnabled"
34 | },
35 | {
36 | .feature = GOA_PROVIDER_FEATURE_CALENDAR,
37 | .key = "CalendarEnabled"
38 | },
39 | {
40 | .feature = GOA_PROVIDER_FEATURE_CONTACTS,
41 | .key = "ContactsEnabled"
42 | },
43 | {
44 | .feature = GOA_PROVIDER_FEATURE_CHAT,
45 | .key = "ChatEnabled"
46 | },
47 | {
48 | .feature = GOA_PROVIDER_FEATURE_DOCUMENTS,
49 | .key = "DocumentsEnabled"
50 | },
51 | {
52 | .feature = GOA_PROVIDER_FEATURE_MUSIC,
53 | .key = "MusicEnabled"
54 | },
55 | {
56 | .feature = GOA_PROVIDER_FEATURE_PHOTOS,
57 | .key = "PhotosEnabled"
58 | },
59 | {
60 | .feature = GOA_PROVIDER_FEATURE_FILES,
61 | .key = "FilesEnabled"
62 | },
63 | {
64 | .feature = GOA_PROVIDER_FEATURE_TICKETING,
65 | .key = "TicketingEnabled"
66 | },
67 | {
68 | .feature = GOA_PROVIDER_FEATURE_READ_LATER,
69 | .key = "ReadLaterEnabled"
70 | },
71 | {
72 | .feature = GOA_PROVIDER_FEATURE_PRINTERS,
73 | .key = "PrintersEnabled"
74 | },
75 | {
76 | .feature = GOA_PROVIDER_FEATURE_MAPS,
77 | .key = "MapsEnabled"
78 | },
79 | {
80 | .feature = GOA_PROVIDER_FEATURE_INVALID,
81 | .key = NULL
82 | }
83 | };
84 |
85 | static void
86 | get_all (GObject *source_object, GAsyncResult *res, gpointer user_data)
87 | {
88 | GError *error;
89 | GList *providers = NULL;
90 | GList *l;
91 | GMainLoop *loop = (GMainLoop *) user_data;
92 | GKeyFile *key_file = NULL;
93 | gchar *key_file_data = NULL;
94 |
95 | error = NULL;
96 | if (!goa_provider_get_all_finish (&providers, res, &error))
97 | {
98 | g_warning ("Unable to get list of providers: %s", error->message);
99 | g_error_free (error);
100 | goto out;
101 | }
102 |
103 | key_file = g_key_file_new ();
104 |
105 | for (l = providers; l != NULL; l=l->next)
106 | {
107 | GoaProvider *provider = GOA_PROVIDER (l->data);
108 | GoaProviderFeatures features;
109 | const gchar *type;
110 | gchar *group;
111 | guint i;
112 |
113 | features = goa_provider_get_provider_features (provider);
114 | if (features == GOA_PROVIDER_FEATURE_INVALID)
115 | continue;
116 |
117 | type = goa_provider_get_provider_type (provider);
118 | group = g_strconcat ("Provider ", type, NULL);
119 |
120 | for (i = 0; provider_features_info[i].key != NULL; i++)
121 | {
122 | if ((features & provider_features_info[i].feature) != 0)
123 | {
124 | const gchar *key = provider_features_info[i].key;
125 |
126 | /* The IMAP/SMTP provider uses Enabled instead of
127 | * MailEnabled. We should probably fix it for consistency.
128 | */
129 | if (g_strcmp0 (type, "imap_smtp") == 0 && g_strcmp0 (key, "MailEnabled") == 0)
130 | key = "Enabled";
131 |
132 | g_key_file_set_boolean (key_file, group, key, TRUE);
133 | }
134 | }
135 |
136 | g_free (group);
137 | }
138 |
139 | error = NULL;
140 | key_file_data = g_key_file_to_data (key_file, NULL, &error);
141 | if (error != NULL)
142 | {
143 | g_warning ("Unable to serialize key file: %s", error->message);
144 | g_error_free (error);
145 | goto out;
146 | }
147 |
148 | g_print ("%s", key_file_data);
149 |
150 | out:
151 | g_clear_pointer (&key_file, (GDestroyNotify) g_key_file_unref);
152 | g_free (key_file_data);
153 | g_list_free_full (providers, g_object_unref);
154 | g_main_loop_quit (loop);
155 | }
156 |
157 | gint
158 | main (void)
159 | {
160 | GMainLoop *loop;
161 |
162 | setlocale (LC_ALL, "");
163 |
164 | /* Workaround https://bugzilla.gnome.org/show_bug.cgi?id=674885. */
165 | g_type_ensure (G_TYPE_DBUS_CONNECTION);
166 |
167 | loop = g_main_loop_new (NULL, FALSE);
168 |
169 | goa_provider_get_all (get_all, loop);
170 | g_main_loop_run (loop);
171 |
172 | g_main_loop_unref (loop);
173 | return 0;
174 | }
175 |
--------------------------------------------------------------------------------