├── .gitignore ├── .gitmodules ├── AUTHORS ├── COPYING ├── COPYING.BSD3 ├── COPYING.MIT ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── admin ├── Makefile.am ├── cockpit │ └── fleet-commander-admin │ │ ├── .eslintignore │ │ ├── .eslintrc.json │ │ ├── css │ │ ├── bootstrap-4.0.0.min.css │ │ └── main.css │ │ ├── img │ │ └── goa │ │ │ ├── exchange.png │ │ │ ├── facebook.png │ │ │ ├── flickr.png │ │ │ ├── foursquare.png │ │ │ ├── google.png │ │ │ ├── imap_smtp.png │ │ │ ├── kerberos.png │ │ │ ├── lastfm.png │ │ │ ├── owncloud.png │ │ │ ├── pocket.png │ │ │ ├── telepathy │ │ │ └── jabber.png │ │ │ └── windows_live.png │ │ ├── index.html │ │ ├── js │ │ ├── base.js │ │ ├── bootstrap-4.0.0.min.js │ │ ├── collectors.js │ │ ├── dialogs.js │ │ ├── fcdbusclient.js │ │ ├── fcspiceclient.js │ │ ├── goa.js │ │ ├── highlightedapps.js │ │ ├── index.js │ │ ├── jquery-3.3.1.min.js │ │ └── livesession.js │ │ ├── livesession.html │ │ ├── manifest.json │ │ └── package.json └── fleetcommander │ ├── __init__.py │ ├── constants.py.in │ ├── database.py │ ├── fcad.py │ ├── fcdbus.py │ ├── fcfreeipa.py │ ├── goa.py │ ├── libvirtcontroller.py │ ├── mergers.py │ ├── sshcontroller.py │ └── utils.py ├── autogen.sh ├── configure.ac ├── data ├── 81-fleet-commander-logger.rules ├── Makefile.am ├── fc-admin.png ├── fc-chromium-policies.json ├── fc-goa-providers.ini ├── firefox-bookmark-fclogger.in ├── firefox_bookmark_fclogger.json.in ├── fleet-commander-admin.conf.in ├── fleet-commander-admin.in ├── fleet-commander-logger.desktop.in ├── fleet-commander-logger.in ├── org.freedesktop.FleetCommander.admin.metainfo.xml └── org.freedesktop.FleetCommander.service.in ├── fleet-commander-admin.spec ├── logger ├── Makefile.am ├── firefox-extension │ ├── bookmarklogger.js │ ├── icons │ │ ├── fc-48.png │ │ └── fc-96.png │ └── manifest.json ├── firefox_bookmark_fclogger.py ├── fleet_commander_logger.py └── {c73e87a7-b5a1-4b6f-b10b-0bd70241a64d}.xpi ├── m4 └── as-ac-expand.m4 ├── package-requirements.txt ├── pylint_plugins.py ├── pylintrc ├── pyproject.toml ├── tests ├── Makefile.am ├── __init__.py ├── _fcdbus_tests.py ├── _logger_nm.py ├── _logger_test_suite.py ├── _mock_dbus.py ├── _mock_nm_dbus.py ├── _mock_realmd_dbus.py ├── _wait_for_name.py ├── azure │ ├── azure-pipelines.yml │ └── templates │ │ ├── build-fedora.yml │ │ ├── configure-fedora.yml │ │ ├── prepare-build-fedora.yml │ │ ├── prepare-lint-fedora.yml │ │ ├── publish-build.yml │ │ ├── variables-common.yml │ │ ├── variables-fedora.yml │ │ └── variables.yml ├── data │ ├── fc_goa_providers_test.ini │ ├── fleet-commander-logger │ │ └── fc-chromium-policies.json │ ├── libvirt_domain-modified-direct-debug.xml │ ├── libvirt_domain-modified-direct-plain-debug.xml │ ├── libvirt_domain-modified-direct-plain.xml │ ├── libvirt_domain-modified-direct.xml │ ├── libvirt_domain-modified-html5-debug.xml │ ├── libvirt_domain-modified-html5.xml │ ├── libvirt_domain-nospice.xml │ ├── libvirt_domain-orig.xml │ └── test.gschema.xml ├── directorymock.py ├── fcdbusclient.py ├── freeipamock.py ├── ldapmock.py ├── libvirtmock.py ├── python-wrapper.sh ├── smbmock.py ├── test_database.py ├── test_fcad.py ├── test_fcdbus.sh ├── test_fcdbus_service.py ├── test_freeipa.py ├── test_libvirt_controller.py ├── test_logger_chromium.py ├── test_logger_connmgr.py ├── test_logger_dconf.sh ├── test_logger_firefox.py ├── test_logger_main.py ├── test_logger_nm.sh ├── test_mergers.py ├── test_sshcontroller.py └── tools │ ├── ssh │ ├── ssh-keygen │ ├── ssh-keyscan │ └── ssh-session-mock └── tools ├── chrome-prefs-extract.py └── introspect_goa_providers.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Autotools related 2 | aclocal.m4 3 | autom4te.cache/ 4 | config.log 5 | config.status 6 | configure 7 | Makefile 8 | Makefile.in 9 | */Makefile 10 | */Makefile.in 11 | install-sh 12 | missing 13 | INSTALL 14 | 15 | # RPM building 16 | rpmbuild/ 17 | dist/ 18 | 19 | # Test suite 20 | tests/*.trs 21 | tests/*.log 22 | test-driver 23 | 24 | # Python related 25 | *.py[co] 26 | __pycache__ 27 | 28 | # Editors and IDEs 29 | *.sublime-project 30 | *.sublime-workspace 31 | .vscode 32 | *.code-workspace 33 | .*.swp 34 | */.*.swp 35 | 36 | # Project specifics 37 | admin/fleetcommander/constants.py 38 | data/*.service 39 | data/fleet-commander-logger.desktop 40 | data/fleet-commander-admin.conf 41 | data/fleet-commander-admin 42 | data/fleet-commander-logger 43 | data/firefox-bookmark-fclogger 44 | data/firefox_bookmark_fclogger.json 45 | tests/data/gschemas.compiled 46 | fleet-commander*.tar.[gx]z 47 | id_rsa 48 | id_rsa.pub 49 | known_hosts 50 | database.db 51 | build-rpm.sh 52 | build-full.sh 53 | install-rpm.sh 54 | install-ipamaster.sh 55 | build-copr.sh 56 | check.sh 57 | check-full.sh 58 | 59 | # web plugin 60 | admin/cockpit/fleet-commander-admin/node_modules/ 61 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "admin/cockpit/fleet-commander-admin/js/spice-html5"] 2 | path = admin/cockpit/fleet-commander-admin/js/spice-html5 3 | url = git://anongit.freedesktop.org/spice/spice-html5 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/AUTHORS -------------------------------------------------------------------------------- /COPYING.BSD3: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 2 | 3 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4 | 5 | Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8 | -------------------------------------------------------------------------------- /COPYING.MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining 2 | a copy of this software and associated documentation files (the 3 | "Software"), to deal in the Software without restriction, including 4 | without limitation the rights to use, copy, modify, merge, publish, 5 | distribute, sublicense, and/or sell copies of the Software, and to 6 | permit persons to whom the Software is furnished to do so, subject to 7 | the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be 10 | included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 13 | EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 14 | WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 15 | 16 | IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, 17 | INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER 18 | RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF 19 | THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT 20 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | 22 | In addition, the following condition applies: 23 | 24 | All redistributions must retain an intact copy of this copyright notice 25 | and disclaimer. -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | RPMBUILD ?= $(abs_builddir)/rpmbuild 2 | TARBALL = $(PACKAGE)-$(VERSION).tar.xz 3 | NULL = 4 | 5 | AM_DISTCHECK_CONFIGURE_FLAGS = \ 6 | --with-udevrulesdir='$$(prefix)/$(udevrulesdir)' \ 7 | $(NULL) 8 | 9 | SUBDIRS = data logger admin tests 10 | 11 | EXTRA_DIST = \ 12 | $(wildcard LICENSE.*) \ 13 | $(wildcard COPYING.*) 14 | 15 | GENERATED_PYTHON_FILES = \ 16 | admin/fleetcommander/constants.py \ 17 | $(NULL) 18 | 19 | .PHONY: prep_src rpmroot rpmdistdir rpms 20 | 21 | prep_src: rpmroot dist-xz 22 | cp "$(top_builddir)/$(TARBALL)" "$(RPMBUILD)/SOURCES/" 23 | 24 | rpms: prep_src rpmroot rpmdistdir 25 | rpmbuild \ 26 | --define "_topdir $(RPMBUILD)" \ 27 | -ba \ 28 | "$(top_builddir)/$(PACKAGE).spec" 29 | cp "$(RPMBUILD)"/RPMS/*/*.rpm "$(top_builddir)/dist/rpms/" 30 | cp "$(RPMBUILD)"/SRPMS/*.src.rpm "$(top_builddir)/dist/srpms/" 31 | 32 | rpmroot: 33 | mkdir -p "$(RPMBUILD)/BUILD" 34 | mkdir -p "$(RPMBUILD)/RPMS" 35 | mkdir -p "$(RPMBUILD)/SOURCES" 36 | mkdir -p "$(RPMBUILD)/SPECS" 37 | mkdir -p "$(RPMBUILD)/SRPMS" 38 | 39 | rpmdistdir: 40 | mkdir -p "$(top_builddir)/dist/rpms" 41 | mkdir -p "$(top_builddir)/dist/srpms" 42 | 43 | clean-local: 44 | rm -rf "$(RPMBUILD)" 45 | rm -rf "$(top_builddir)/dist" 46 | rm -f "$(top_builddir)"/$(PACKAGE)-*.tar.gz 47 | 48 | .PHONY: pylint 49 | pylint: $(GENERATED_PYTHON_FILES) 50 | FILES=`find $(top_srcdir) \ 51 | -type d -exec test -e '{}/__init__.py' \; -print -prune -o \ 52 | -path './rpmbuild' -prune -o \ 53 | -name '*.py' -print | sort`; \ 54 | echo -e "Pylinting files:\n$${FILES}\n"; \ 55 | $(PYTHON) -m pylint --version; \ 56 | PYTHONPATH=$(top_srcdir):$(top_srcdir)/admin $(PYTHON) -m pylint \ 57 | --rcfile=$(top_srcdir)/pylintrc \ 58 | --load-plugins pylint_plugins \ 59 | $${FILES} 60 | 61 | .PHONY: black 62 | black: $(GENERATED_PYTHON_FILES) 63 | $(PYTHON) -m black -v \ 64 | $(top_srcdir) 65 | 66 | .PHONY: blackcheck 67 | blackcheck: $(GENERATED_PYTHON_FILES) 68 | $(PYTHON) -m black -v --check --diff \ 69 | $(top_srcdir) 70 | 71 | .PHONY: eslint 72 | eslint: 73 | cd admin/cockpit/fleet-commander-admin; \ 74 | npm install; \ 75 | npm run eslint 76 | 77 | .PHONY: eslint-fix 78 | eslint-fix: 79 | cd admin/cockpit/fleet-commander-admin; \ 80 | npm install; \ 81 | npm run eslint:fix 82 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Fleet Commander 2 | =============== 3 | 4 | Fleet Commander is an application that allows you to manage the desktop 5 | configuration of a large network of users and workstations/laptops. 6 | 7 | It is primarily targeted to Linux systems based on the GNOME desktop. 8 | 9 | Fleet Commander consists on two components: 10 | 11 | * a web service integrated with Apache that serves the dynamic application and 12 | the profile data to the network. 13 | * and a client side daemon that runs on every host of the network. 14 | 15 | Fleet Commander relies on libvirt and KVM to generate the profile data 16 | dynamically from a template VM running the same environment as the rest of the 17 | network. 18 | 19 | SETUP 20 | ----- 21 | 22 | These are the instructions to build and install the admin interface: 23 | 24 | ``` 25 | $ ./configure --prefix=$PREFIX # where $PREFIX can be /usr or /usr/local 26 | $ make 27 | $ make install 28 | $ mkdir -p /var/lib/fleet-commander-admin/profiles 29 | ``` 30 | 31 | These are the instructions to install the logger and enable a VM as a Fleet Commander template: 32 | 33 | ``` 34 | $ ./configure --prefix=/usr 35 | $ make 36 | $ cd logger 37 | $ make install 38 | $ cd ../data/ 39 | $ make install 40 | ``` 41 | 42 | The install prefix must be set to /usr so that the fleet-commander-logger.desktop 43 | file makes it to the /etc/xdg/autostart directory. 44 | 45 | NOTE ON THE LOGGER 46 | ------------------ 47 | 48 | The logger autostarts on a desktop session only when a special device shows up 49 | in /dev/virtio-ports 50 | 51 | RUNNING THE ADMIN INTERFACE 52 | --------------------------- 53 | 54 | Fleet Commander is a plugin for Cockpit. You should already have an installation 55 | of Cockpit in your machine. If not, install it first following the instructions 56 | at http://cockpit-project.org/running.html 57 | 58 | If you have used the /usr prefix, Fleet Commander plugin is already installed in 59 | the Cockpit plugin folder. If you chosen something different like /usr/local 60 | you can enable fleet commander executing the following command as root: 61 | 62 | ``` 63 | # ln -s /usr/local/share/fleet-commander-admin/cockpit/fleet-commander-admin \ 64 | /usr/share/cockpit/ 65 | ``` 66 | 67 | Then, logout from cockpit if you are already logged in, and when you login 68 | again Fleet Commander will be available under Tools option. 69 | 70 | Once in Fleet Commander, just follow the on-screen instructions. 71 | -------------------------------------------------------------------------------- /admin/Makefile.am: -------------------------------------------------------------------------------- 1 | fc_admin_pydir = ${fcpythondir}/fleetcommander 2 | fc_admin_py_SCRIPTS = \ 3 | fleetcommander/__init__.py \ 4 | fleetcommander/mergers.py \ 5 | fleetcommander/database.py \ 6 | fleetcommander/fcdbus.py \ 7 | fleetcommander/fcfreeipa.py \ 8 | fleetcommander/fcad.py \ 9 | fleetcommander/goa.py \ 10 | fleetcommander/libvirtcontroller.py \ 11 | fleetcommander/sshcontroller.py \ 12 | fleetcommander/utils.py 13 | 14 | fc_admin_constsdir = ${fcpythondir}/fleetcommander 15 | fc_admin_consts_in_files = fleetcommander/constants.py.in 16 | fc_admin_consts_SCRIPTS = fleetcommander/constants.py 17 | 18 | fc_jsdir = ${datarootdir}/cockpit/fleet-commander-admin/js 19 | fc_js_DATA = \ 20 | cockpit/fleet-commander-admin/js/jquery-3.3.1.min.js \ 21 | cockpit/fleet-commander-admin/js/bootstrap-4.0.0.min.js \ 22 | cockpit/fleet-commander-admin/js/base.js \ 23 | cockpit/fleet-commander-admin/js/dialogs.js \ 24 | cockpit/fleet-commander-admin/js/fcdbusclient.js \ 25 | cockpit/fleet-commander-admin/js/fcspiceclient.js \ 26 | cockpit/fleet-commander-admin/js/collectors.js \ 27 | cockpit/fleet-commander-admin/js/index.js \ 28 | cockpit/fleet-commander-admin/js/highlightedapps.js \ 29 | cockpit/fleet-commander-admin/js/goa.js \ 30 | cockpit/fleet-commander-admin/js/livesession.js 31 | 32 | fc_goaimgdir = ${datarootdir}/cockpit/fleet-commander-admin/img/goa 33 | fc_goaimg_DATA = \ 34 | cockpit/fleet-commander-admin/img/goa/exchange.png \ 35 | cockpit/fleet-commander-admin/img/goa/facebook.png \ 36 | cockpit/fleet-commander-admin/img/goa/flickr.png \ 37 | cockpit/fleet-commander-admin/img/goa/foursquare.png \ 38 | cockpit/fleet-commander-admin/img/goa/google.png \ 39 | cockpit/fleet-commander-admin/img/goa/imap_smtp.png \ 40 | cockpit/fleet-commander-admin/img/goa/kerberos.png \ 41 | cockpit/fleet-commander-admin/img/goa/lastfm.png \ 42 | cockpit/fleet-commander-admin/img/goa/owncloud.png \ 43 | cockpit/fleet-commander-admin/img/goa/pocket.png \ 44 | cockpit/fleet-commander-admin/img/goa/windows_live.png 45 | 46 | fc_goatelepathyimgdir = ${datarootdir}/cockpit/fleet-commander-admin/img/goa/telepathy 47 | fc_goatelepathyimg_DATA = \ 48 | cockpit/fleet-commander-admin/img/goa/telepathy/jabber.png 49 | 50 | fc_spicehtml5dir = ${datarootdir}/cockpit/fleet-commander-admin/js/spice-html5/src 51 | fc_spicehtml5_DATA = \ 52 | cockpit/fleet-commander-admin/js/spice-html5/src/cursor.js \ 53 | cockpit/fleet-commander-admin/js/spice-html5/src/bitmap.js \ 54 | cockpit/fleet-commander-admin/js/spice-html5/src/playback.js \ 55 | cockpit/fleet-commander-admin/js/spice-html5/src/spiceconn.js \ 56 | cockpit/fleet-commander-admin/js/spice-html5/src/ticket.js \ 57 | cockpit/fleet-commander-admin/js/spice-html5/src/filexfer.js \ 58 | cockpit/fleet-commander-admin/js/spice-html5/src/quic.js \ 59 | cockpit/fleet-commander-admin/js/spice-html5/src/main.js \ 60 | cockpit/fleet-commander-admin/js/spice-html5/src/webm.js \ 61 | cockpit/fleet-commander-admin/js/spice-html5/src/spicetype.js \ 62 | cockpit/fleet-commander-admin/js/spice-html5/src/simulatecursor.js \ 63 | cockpit/fleet-commander-admin/js/spice-html5/src/enums.js \ 64 | cockpit/fleet-commander-admin/js/spice-html5/src/inputs.js \ 65 | cockpit/fleet-commander-admin/js/spice-html5/src/port.js \ 66 | cockpit/fleet-commander-admin/js/spice-html5/src/atKeynames.js \ 67 | cockpit/fleet-commander-admin/js/spice-html5/src/display.js \ 68 | cockpit/fleet-commander-admin/js/spice-html5/src/png.js \ 69 | cockpit/fleet-commander-admin/js/spice-html5/src/spicearraybuffer.js \ 70 | cockpit/fleet-commander-admin/js/spice-html5/src/resize.js \ 71 | cockpit/fleet-commander-admin/js/spice-html5/src/spicemsg.js \ 72 | cockpit/fleet-commander-admin/js/spice-html5/src/wire.js \ 73 | cockpit/fleet-commander-admin/js/spice-html5/src/lz.js \ 74 | cockpit/fleet-commander-admin/js/spice-html5/src/utils.js \ 75 | cockpit/fleet-commander-admin/js/spice-html5/src/spicedataview.js 76 | 77 | fc_spicehtml5thirdpartydir = ${datarootdir}/cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty 78 | fc_spicehtml5thirdparty_DATA = \ 79 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/browser-es-module-loader/dist/browser-es-module-loader.js \ 80 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/prng4.js \ 81 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/rsa.js \ 82 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/sha1.js \ 83 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/rng.js \ 84 | cockpit/fleet-commander-admin/js/spice-html5/src/thirdparty/jsbn.js 85 | 86 | fc_cockpitdir = ${datarootdir}/cockpit/fleet-commander-admin 87 | fc_cockpit_DATA = \ 88 | cockpit/fleet-commander-admin/index.html \ 89 | cockpit/fleet-commander-admin/livesession.html \ 90 | cockpit/fleet-commander-admin/manifest.json 91 | 92 | fc_cssdir = ${datarootdir}/cockpit/fleet-commander-admin/css 93 | fc_css_DATA = \ 94 | cockpit/fleet-commander-admin/css/bootstrap-4.0.0.min.css \ 95 | cockpit/fleet-commander-admin/css/main.css 96 | 97 | EXTRA_DIST = \ 98 | $(fc_admin_py_SCRIPTS) \ 99 | $(fc_js_DATA) \ 100 | $(fc_spicehtml5_DATA) \ 101 | $(fc_spicehtml5thirdparty_DATA) \ 102 | $(fc_cockpit_DATA) \ 103 | $(fc_css_DATA) \ 104 | $(fc_goaimg_DATA) \ 105 | $(fc_goatelepathyimg_DATA) \ 106 | $(fc_admin_consts_in_files) 107 | 108 | # CLEANFILES = \ 109 | # $(fc_admin_consts_SCRIPTS) 110 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | js/spice-html5/* 3 | js/jquery-3.3.1.min.js 4 | js/bootstrap-4.0.0.min.js 5 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es6": true, 6 | "jquery": true 7 | }, 8 | "extends": [ 9 | "eslint:recommended", 10 | "standard" 11 | ], 12 | "parserOptions": { 13 | "sourceType": "module" 14 | }, 15 | "rules": { 16 | "indent": ["error", 4, 17 | { 18 | "ObjectExpression": "first", 19 | "CallExpression": {"arguments": "first"}, 20 | "MemberExpression": 2 21 | }], 22 | "quotes": "off", 23 | "camelcase": "off", 24 | "comma-dangle": "off", 25 | "semi": ["error", "always", { "omitLastInOneLineBlock": true }], 26 | "space-before-function-paren": "off" 27 | }, 28 | "globals": { 29 | "cockpit": "readonly" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program 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.1 of the licence, or (at your option) any later version. 8 | * 9 | * This program 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 Public 15 | * License along with this program; if not, see . 16 | * 17 | * Authors: Alberto Ruiz 18 | * Oliver Gutiérrez 19 | */ 20 | 21 | body.fleet-commander .modal { 22 | padding-top: 140px; 23 | } 24 | 25 | #main-container, #curtain { 26 | display: none; 27 | } 28 | 29 | #event-logs-dialog { 30 | width: 90%; 31 | overflow: auto; 32 | } 33 | 34 | #domain-selection-list { 35 | max-height: 600px; 36 | overflow: auto; 37 | } 38 | 39 | #selected-changes-form { 40 | max-height: 600px; 41 | overflow: auto; 42 | } 43 | 44 | #change-item-template { 45 | display: none; 46 | } 47 | 48 | .grayed { 49 | background-color: lightgray; 50 | } 51 | 52 | #goa-current-provider-icon { 53 | width: 96px; 54 | height: 96px; 55 | margin: 2px; 56 | } 57 | 58 | .goa-provider-icon { 59 | width: 2.5em; 60 | height: 2.5em; 61 | margin: 0 2px; 62 | } 63 | 64 | .list-view-pf-checkbox { 65 | padding: 0 3px; 66 | margin: 0; 67 | margin-right: 15px; 68 | } 69 | 70 | .list-view-pf-main-info { 71 | padding: 0; 72 | } 73 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/exchange.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/facebook.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/flickr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/flickr.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/foursquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/foursquare.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/google.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/imap_smtp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/imap_smtp.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/kerberos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/kerberos.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/lastfm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/lastfm.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/owncloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/owncloud.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/pocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/pocket.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/telepathy/jabber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/telepathy/jabber.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/img/goa/windows_live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fleet-commander/fc-admin/0202f6ac8a2d969819599114b014f58133beb991/admin/cockpit/fleet-commander-admin/img/goa/windows_live.png -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/js/base.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program 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.1 of the licence, or (at your option) any later version. 8 | * 9 | * This program 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 Public 15 | * License along with this program; if not, see . 16 | * 17 | * Authors: Alberto Ruiz 18 | * Oliver Gutiérrez 19 | */ 20 | 21 | /******************************************************************************* 22 | * Utility functions 23 | ******************************************************************************/ 24 | 25 | let DEBUG = 0; 26 | let DEBUG_FC_PROTOCOL = 0; 27 | 28 | function clearModalFormErrors(modalId) { 29 | $('#' + modalId + ' div.form-group').removeClass('has-error'); 30 | $('#' + modalId + ' div.form-group > .error-message').remove(); 31 | } 32 | 33 | function hasForm(fieldId) { 34 | const groupId = `#${fieldId}-group`; 35 | if ($(groupId).length) { 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | function addFormError(fieldId, errorMessage) { 42 | const groupId = `#${fieldId}-group`; 43 | $(groupId).append( 44 | '
' + 45 | errorMessage + 46 | '
' 47 | ); 48 | $(groupId).addClass('has-error'); 49 | } 50 | 51 | function hasSuffix(haystack, needle) { 52 | return (haystack.length - needle.length) === haystack.lastIndexOf(needle); 53 | } 54 | 55 | function setDebugLevel(level, debug_protocol = false) { 56 | switch (level) { 57 | case 'debug': 58 | DEBUG = 3; 59 | break; 60 | case 'info': 61 | case 'warning': 62 | DEBUG = 2; 63 | break; 64 | case 'error': 65 | DEBUG = 1; 66 | break; 67 | default: 68 | DEBUG = 0; 69 | } 70 | 71 | if (DEBUG > 0) { 72 | console.log('Debug level set to ' + DEBUG); 73 | } 74 | 75 | if (debug_protocol === true) { 76 | DEBUG_FC_PROTOCOL = 1; 77 | } else { 78 | DEBUG_FC_PROTOCOL = 0; 79 | } 80 | if (DEBUG > 0) { 81 | console.log('Debug of FC Logger protocol', DEBUG_FC_PROTOCOL); 82 | } 83 | } 84 | 85 | export { 86 | DEBUG, 87 | DEBUG_FC_PROTOCOL, 88 | addFormError, 89 | clearModalFormErrors, 90 | hasForm, 91 | hasSuffix, 92 | setDebugLevel 93 | }; 94 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/js/collectors.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program 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.1 of the licence, or (at your option) any later version. 8 | * 9 | * This program 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 Public 15 | * License along with this program; if not, see . 16 | * 17 | * Author: Oliver Gutiérrez 18 | */ 19 | 20 | import { DEBUG } from './base.js'; 21 | 22 | function BaseCollector(namespace) { 23 | this.namespace = namespace; 24 | this.changes = {}; 25 | this.key_name = 'key'; 26 | } 27 | 28 | BaseCollector.prototype = { 29 | 30 | get_key_from_change: function (change) { 31 | if (change[this.key_name] !== undefined) { 32 | return change[this.key_name]; 33 | } 34 | return undefined; 35 | }, 36 | 37 | get_value_from_change: function (change) { 38 | if (change.value !== undefined) { 39 | return change.value; 40 | } 41 | return undefined; 42 | }, 43 | 44 | handle_change: function (change) { 45 | if (DEBUG > 0) { 46 | console.log( 47 | 'FC: Collector', 48 | this.namespace, 49 | 'handling change', 50 | change 51 | ); 52 | } 53 | const key = this.get_key_from_change(change); 54 | if (key !== undefined) { 55 | this.changes[key] = change; 56 | } else { 57 | if (DEBUG > 0) { 58 | console.log( 59 | 'FC: Collector', 60 | this.namespace, 61 | 'can not handle change', 62 | change 63 | ); 64 | } 65 | } 66 | }, 67 | 68 | dump_changes: function () { 69 | const self = this; 70 | const changelist = []; 71 | $.each(this.changes, function (k, v) { 72 | changelist.push([k, self.get_value_from_change(v)]); 73 | }); 74 | return changelist; 75 | }, 76 | 77 | get_changeset: function (selected_keys) { 78 | const self = this; 79 | const changeset = []; 80 | $.each(selected_keys, function (ignore, key) { 81 | if (self.changes[key] !== undefined) { 82 | changeset.push(self.changes[key]); 83 | } 84 | }); 85 | return changeset; 86 | } 87 | }; 88 | 89 | // Network Manager specific collector 90 | function NMCollector(namespace) { 91 | BaseCollector.apply(this, [namespace]); 92 | this.key_name = 'uuid'; 93 | } 94 | 95 | NMCollector.prototype = Object.create(BaseCollector.prototype); 96 | 97 | NMCollector.prototype.get_value_from_change = function (change) { 98 | if (change.type !== undefined && change.id !== undefined) { 99 | return change.type + ' - ' + change.id; 100 | } 101 | return undefined; 102 | }; 103 | 104 | // Firefox bookmarks specific collector 105 | function FirefoxBookmarksCollector(namespace) { 106 | BaseCollector.apply(this, [namespace]); 107 | } 108 | 109 | FirefoxBookmarksCollector.prototype = Object.create(BaseCollector.prototype); 110 | 111 | FirefoxBookmarksCollector.prototype.get_value_from_change = function (change) { 112 | return change.value.URL + ' - ' + change.value.Title; 113 | }; 114 | 115 | export { BaseCollector, NMCollector, FirefoxBookmarksCollector }; 116 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/js/dialogs.js: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019 FleetCommander Contributors see COPYING for license 3 | // 4 | 5 | /******************************************************************************* 6 | * Dialogs 7 | ******************************************************************************/ 8 | 9 | const _ = cockpit.gettext; 10 | 11 | function BaseDialog(id) { 12 | const self = this; 13 | const hidn_ev = 'hidden.bs.modal'; 14 | const shn_ev = 'shown.bs.modal'; 15 | this.id = id; 16 | 17 | /* state can be 'hide', 'show' or 'notset' */ 18 | this.state = 'hide'; 19 | 20 | $(this.id).off(hidn_ev).on(hidn_ev, function () { 21 | if (self.state === 'show') { 22 | $(this).modal('show'); 23 | } 24 | self.state = 'notset'; 25 | }); 26 | 27 | $(this.id).off(shn_ev).on(shn_ev, function () { 28 | if (self.state === 'hide') { 29 | $(this).modal('hide'); 30 | } 31 | self.state = 'notset'; 32 | }); 33 | } 34 | 35 | BaseDialog.prototype = { 36 | show: function () { 37 | this.state = 'show'; 38 | $(this.id).modal('show'); 39 | }, 40 | close: function () { 41 | this.state = 'hide'; 42 | $(this.id).modal('hide'); 43 | } 44 | }; 45 | 46 | function SpinnerDialog() { 47 | const id = '#spinner-dialog-modal'; 48 | const default_title = _('Loading'); 49 | BaseDialog.apply(this, [id]); 50 | 51 | this.show = function (message, title) { 52 | title = title || default_title; 53 | $(id + ' h4').html(title); 54 | $(id + ' .modal-body p').html(message); 55 | BaseDialog.prototype.show.apply(this); 56 | }; 57 | } 58 | 59 | SpinnerDialog.prototype = Object.create(BaseDialog.prototype); 60 | SpinnerDialog.prototype.constructor = SpinnerDialog; 61 | 62 | function QuestionDialog() { 63 | const self = this; 64 | const id = '#question-dialog-modal'; 65 | const default_title = _('Question'); 66 | BaseDialog.apply(this, [id]); 67 | 68 | this.show = function (message, title, acceptcb, cancelcb) { 69 | title = title || default_title; 70 | cancelcb = cancelcb || function () { self.close() }; 71 | $(id + ' h4').html(title); 72 | $(id + ' .modal-body').html(message); 73 | $(id + ' .modal-footer').html(''); 74 | $('' 145 | ); 146 | button.click(data.callback); 147 | buttonsarea.append(button); 148 | buttonsarea.append(' '); 149 | }); 150 | $('#curtain').show(); 151 | } 152 | 153 | const spinnerDialog = new SpinnerDialog(); 154 | const questionDialog = new QuestionDialog(); 155 | const messageDialog = new MessageDialog(); 156 | 157 | export { spinnerDialog, questionDialog, messageDialog, showCurtain }; 158 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/js/fcspiceclient.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program 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.1 of the licence, or (at your option) any later version. 8 | * 9 | * This program 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 Public 15 | * License along with this program; if not, see . 16 | * 17 | * Authors: Alberto Ruiz 18 | * Oliver Gutiérrez 19 | */ 20 | 21 | import { DEBUG } from './base.js'; 22 | import { spinnerDialog, messageDialog } from './dialogs.js'; 23 | import * as SpiceHtml5 from './spice-html5/src/main.js'; 24 | 25 | const _ = cockpit.gettext; 26 | 27 | function FleetCommanderSpiceClient(details, error_cb, spice_error_cb, timeout) { 28 | const self = this; 29 | 30 | this.conn_timeout = timeout || 15000; // ms 31 | // this.sc; 32 | this.connecting = null; 33 | this.noretry = false; 34 | 35 | this.stop = function () { 36 | if (self.sc) { 37 | self.sc.stop(); 38 | } 39 | }; 40 | 41 | this.set_connection_timeout = function () { 42 | if (!self.connecting) { 43 | self.connecting = setTimeout(function () { 44 | if (self.sc) { 45 | self.sc.stop(); 46 | } 47 | $('#spice-screen').html(''); 48 | self.connecting = null; 49 | self.noretry = true; 50 | if (DEBUG > 0) { 51 | console.log('FC: Connection tries timed out'); 52 | } 53 | spinnerDialog.close(); 54 | messageDialog.show( 55 | _('Connection error to virtual machine.'), 56 | _('Connection error') 57 | ); 58 | }, self.conn_timeout); 59 | } 60 | }; 61 | 62 | this.spice_connected = function () { 63 | if (DEBUG > 0) { 64 | console.log('FC: Connected to virtual machine using SPICE'); 65 | } 66 | spinnerDialog.close(); 67 | if (self.connecting) { 68 | clearTimeout(self.connecting); 69 | self.connecting = null; 70 | } 71 | }; 72 | 73 | this.spice_error = err => { 74 | if (spice_error_cb) { 75 | spice_error_cb(err); 76 | } 77 | }; 78 | 79 | this.do_connection = function () { 80 | if (DEBUG > 0) { 81 | console.log('FC: Connecting to spice session'); 82 | } 83 | 84 | const query = window.btoa( 85 | JSON.stringify({ 86 | payload: 'stream', 87 | protocol: 'binary', 88 | unix: details.path, 89 | binary: 'raw', 90 | }) 91 | ); 92 | 93 | let websocket_proto = 'ws:'; 94 | if (location.protocol === 'https:') { 95 | websocket_proto = 'wss:'; 96 | } 97 | 98 | const cockpit_uri = websocket_proto + '//' + 99 | location.hostname + 100 | ':' + location.port + 101 | '/cockpit/channel/' + 102 | cockpit.transport.csrf_token + 103 | '?' + query; 104 | 105 | if (DEBUG > 0) { 106 | console.log('FC: Cockpit channel websocket uri is:', cockpit_uri); 107 | } 108 | 109 | if (self.sc) { 110 | self.sc.stop(); 111 | } 112 | $('#spice-screen').html(''); 113 | 114 | self.sc = new SpiceHtml5.SpiceMainConn({ 115 | uri: cockpit_uri, // 'ws://' + location.hostname + ':' + port, 116 | password: details.ticket, 117 | screen_id: 'spice-screen', 118 | onsuccess: self.spice_connected, 119 | onerror: self.spice_error 120 | }); 121 | }; 122 | 123 | try { 124 | self.do_connection(); 125 | } catch (e) { 126 | console.error('FC: Fatal error:' + e.toString()); 127 | if (error_cb) { 128 | error_cb(); 129 | } 130 | } 131 | 132 | this.reconnect = function () { 133 | spinnerDialog.show( 134 | _('Connecting to virtual machine. Please wait...'), 135 | _('Reconnecting') 136 | ); 137 | self.do_connection(); 138 | }; 139 | } 140 | 141 | export { FleetCommanderSpiceClient }; 142 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/js/highlightedapps.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Red Hat, Inc. 3 | * 4 | * This program 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.1 of the licence, or (at your option) any later version. 8 | * 9 | * This program 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 Public 15 | * License along with this program; if not, see . 16 | * 17 | * Author: Oliver Gutiérrez 18 | */ 19 | import { DEBUG, hasSuffix, clearModalFormErrors } from './base.js'; 20 | import { messageDialog } from './dialogs.js'; 21 | 22 | const _ = cockpit.gettext; 23 | 24 | class HighlightedApp { 25 | constructor() { 26 | this.currentprofile = null; 27 | 28 | this.add = this.add.bind(this); 29 | this.addFromEntry = this.addFromEntry.bind(this); 30 | this.initialize = this.initialize.bind(this); 31 | this.refresh = this.refresh.bind(this); 32 | this.remove = this.remove.bind(this); 33 | this.save = this.save.bind(this); 34 | this.show = this.show.bind(this); 35 | } 36 | 37 | remove(app) { 38 | $('#highlighted-apps-list li[data-id="' + app + '"]').remove(); 39 | } 40 | 41 | add(app) { 42 | if (typeof app !== "string") { 43 | return; 44 | } 45 | 46 | if (hasSuffix(app, ".desktop") === false) { 47 | return; 48 | } 49 | 50 | const li = $( 51 | '
  • ', 52 | { class: 'list-group-item', 'data-id': app, text: app } 53 | ); 54 | const del = $( 55 | '', 56 | { class: 'pull-right btn btn-danger', text: 'Delete' } 57 | ); 58 | del.click(app, () => { this.remove(app) }); 59 | del.appendTo(li); 60 | li.appendTo($('#highlighted-apps-list')); 61 | } 62 | 63 | refresh() { 64 | if (DEBUG > 0) { 65 | console.log('FC: Refreshing highlighted apps list'); 66 | } 67 | try { 68 | const changes = this.currentprofile().settings["org.gnome.gsettings"]; 69 | $.each(changes, (ignoreIndex, e) => { 70 | for (const key in e) { 71 | if (e[key] === "/org/gnome/software/popular-overrides") { 72 | try { 73 | let overrides = e.value; 74 | if (Array.isArray(overrides) === false) { 75 | if (typeof overrides === 'string' && overrides.startsWith('[') && overrides.endsWith(']')) { 76 | const a = overrides.substring(1, overrides.length - 1); 77 | if (a.length > 0) { 78 | overrides = a.substring(1, a.length - 1).split("','"); 79 | } else { 80 | overrides = null; 81 | } 82 | } else { 83 | overrides = null; 84 | } 85 | } else { 86 | overrides = null; 87 | } 88 | $.each(overrides, (index, value) => { 89 | this.add(value); 90 | }); 91 | return; 92 | } catch (ignore) {} 93 | } 94 | } 95 | }); 96 | } catch (ignore) {} 97 | } 98 | 99 | show() { 100 | $('#highlighted-apps-list').html(''); 101 | $('#profile-modal').modal('hide'); 102 | $('#highlighted-apps-modal').modal('show'); 103 | this.refresh(); 104 | } 105 | 106 | addFromEntry() { 107 | clearModalFormErrors('highlighted-apps-modal'); 108 | 109 | const app = $('#app-name').val(); 110 | 111 | if (hasSuffix(app, ".desktop") === false) { 112 | messageDialog.show( 113 | _('Application identifier must have .desktop extension'), 114 | _('Invalid entry') 115 | ); 116 | return; 117 | } 118 | if (app.indexOf('"') !== -1 || app.indexOf("'") !== -1) { 119 | messageDialog.show( 120 | _('Application identifier must not contain quotes'), 121 | _('Invalid entry') 122 | ); 123 | return; 124 | } 125 | if ($('#highlighted-apps-list li[data-id="' + app + '"]').length > 0) { 126 | messageDialog.show( 127 | _('Application identifier is already in favourites'), 128 | _('Invalid entry') 129 | ); 130 | return; 131 | } 132 | this.add(app); 133 | $('#app-name').val(''); 134 | } 135 | 136 | save() { 137 | const overrides = []; 138 | let changed = false; 139 | $('#highlighted-apps-list li').each(function () { 140 | overrides.push($(this).attr('data-id')); 141 | }); 142 | 143 | const currentprofile = this.currentprofile(); 144 | if (currentprofile.settings["org.gnome.gsettings"] !== undefined) { 145 | $.each(currentprofile.settings["org.gnome.gsettings"], (ignore, e) => { 146 | for (const key in e) { 147 | if (e[key] === "/org/gnome/software/popular-overrides") { 148 | e.value = JSON.stringify(overrides).replace(/"/g, "'"); 149 | changed = true; 150 | break; 151 | } 152 | } 153 | }); 154 | if (!changed) { 155 | currentprofile.settings["org.gnome.gsettings"].push({ 156 | key: '/org/gnome/software/popular-overrides', 157 | value: JSON.stringify(overrides).replace(/"/g, "'"), 158 | signature: 'as' 159 | }); 160 | } 161 | } else { 162 | currentprofile.settings["org.gnome.gsettings"] = [ 163 | { 164 | key: '/org/gnome/software/popular-overrides', 165 | value: JSON.stringify(overrides).replace(/"/g, "'"), 166 | signature: 'as' 167 | } 168 | ]; 169 | } 170 | $('#highlighted-apps-modal').modal('hide'); 171 | $('#profile-modal').modal('show'); 172 | } 173 | 174 | initialize(currentprofile_cb) { 175 | this.currentprofile = currentprofile_cb; 176 | } 177 | } 178 | 179 | const highlightedApp = new HighlightedApp(); 180 | 181 | export { highlightedApp }; 182 | -------------------------------------------------------------------------------- /admin/cockpit/fleet-commander-admin/livesession.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Fleet Commander - Live session 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
    20 |
    21 |

    22 |

    23 |
    24 |
    25 | 26 | 27 | 43 | 44 | 45 | 61 | 62 |
    63 | 64 | 121 | 122 |
    123 |
    124 |
    125 | Virtual Session 126 | 127 | 128 | 129 | 133 | 134 |
    135 |
    136 |
    137 |
    138 |
    139 |
    140 |
    141 |
    142 |
    143 | 144 |
    145 |
    146 |
    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 |