Skip to content
Snippets Groups Projects
Commit 8d2e7c23 authored by Mark Beierl's avatar Mark Beierl
Browse files

Merge branch 'cherry-pick-74517831' into 'v9.0'

Virtual PC for Hackfest

See merge request !130
parents 6f202ff8 42660e4a
No related branches found
No related tags found
1 merge request!130Virtual PC for Hackfest
Pipeline #251 passed with stage
in 1 minute and 28 seconds
Showing
with 1848 additions and 0 deletions
# Descriptor created by OSM descriptor package generated
**Created on 02/18/2021, 05:51:56 **
\ No newline at end of file
# Copyright 2019 ETSI OSM
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
nsd:
nsd:
- description: Virtual Desktop Computer with Xubuntu Desktop and RDP
designer: OSM
df:
- id: default-df
vnf-profile:
- id: '1'
virtual-link-connectivity:
- constituent-cpd-id:
- constituent-base-element-id: '1'
constituent-cpd-id: virtual-pc-mgmt-ext
virtual-link-profile-id: mgmtnet
vnfd-id: virtual-pc_vnfd
id: hackfest_virtual-pc_nsd
name: hackfest_virtual-pc_nsd
version: '1.0'
virtual-link-desc:
- id: mgmtnet
mgmt-network: 'true'
vnfd-id:
- virtual-pc_vnfd
/venv
*.py[cod]
*.charm
This diff is collapsed.
# virtual-pc
## Description
## Usage
### Prepare the environment
```bash
sudo snap install juju --classic --channel 2.8/stable
sudo snap install lxd
lxd.init
juju bootstrap lxd
juju add-model test-virtual-pc
```
### Deploy (from the Store)
```bash
juju deploy cs:~charmed-osm/virtual-pc --channel edge
```
### Deploy (locally)
Build the charm:
```bash
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
pip install charmcraft
./venv/bin/charmcraft build
```
Deploy:
```bash
juju deploy ./virtual-pc.charm
```
## Developing
Create and activate a virtualenv with the development requirements:
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
## Testing
The Python operator framework includes a very nice harness for testing
operator behaviour without full deployment. Just `run_tests`:
./run_tests
# Copyright 2020 ETSI OSM Contributors
# See LICENSE file for licensing details.
#
# This is only an example, and you should edit to suit your needs.
# If you don't need actions, you can remove the file entirely.
# It ties in to the example _on_fortune_action handler in src/charm.py
# Copyright 2020 ETSI OSM Contributors
# See LICENSE file for licensing details.
#
# This is only an example, and you should edit to suit your needs.
# If you don't need config, you can remove the file entirely.
options:
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
name: virtual-pc
description: |
TODO: fill out the charm's description
summary: |
TODO: fill out the charm's summary
series:
- focal
-r requirements.txt
flake8
charmcraft
\ No newline at end of file
ops
#!/bin/sh -e
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
if [ -z "$VIRTUAL_ENV" -a -d venv/ ]; then
. venv/bin/activate
fi
if [ -z "$PYTHONPATH" ]; then
export PYTHONPATH=src
else
export PYTHONPATH="src:$PYTHONPATH"
fi
flake8
python3 -m unittest -v "$@"
#!/usr/bin/env python3
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
from apt.progress.base import InstallProgress
import logging
import os
import shutil
from jinja2 import Template
from ops.charm import CharmBase
from ops.framework import StoredState
from ops.main import main
from ops.model import (
MaintenanceStatus,
ActiveStatus,
# BlockedStatus,
)
from utils import (
service_stop,
service_restart,
install_apt,
shell,
)
# from typing import Dict, Any
logger = logging.getLogger(__name__)
APT_REQUIREMENTS = [
"firefox",
"mate-desktop", # 469 packages
"mate-applets",
"mate-applet-brisk-menu",
"mate-indicator-applet",
"mate-session-manager",
"mate-terminal",
"xrdp",
]
SNAP_INSTALLS = [
"code --classic",
]
POLKIT_TEMPLATE = "./templates/color.pkla"
POLKIT_PATH = "/etc/polkit-1/localauthority/50-local.d/color.pkla"
STARTWM_TEMPLATE = "./templates/startwm.sh"
STARTWM_PATH = "/etc/xrdp/startwm.sh"
# WM_COMMAND = "startxfce4" # xubuntu-desktop
# WM_COMMAND = "budgie-desktop" # budgie-desktop-environment
WM_COMMAND = "mate-session" # mate-desktop
class VirtualPCCharm(CharmBase, InstallProgress):
_stored = StoredState()
def __init__(self, *args):
super().__init__(*args)
InstallProgress.__init__(self)
self._stored.set_default()
# Basic hooks
self.framework.observe(self.on.install, self._on_install)
self.framework.observe(self.on.start, self._on_start)
self.framework.observe(self.on.stop, self._on_stop)
self.framework.observe(self.on.config_changed, self._on_config_changed)
self.framework.observe(self.on.update_status, self._on_update_status)
# Actions hooks
# Relations hooks
# Override InstallProgress to update our status
def status_change(self, pkg, percent, status):
message = str(int(percent)) + "% " + status
self.unit.status = MaintenanceStatus(message)
# Basic hooks
def _on_install(self, _):
self.unit.status = MaintenanceStatus("Installing apt packages")
install_apt(packages=APT_REQUIREMENTS, update=True, progress=self)
service_stop('xrdp')
self.unit.status = MaintenanceStatus("Installing snaps")
for snap in SNAP_INSTALLS:
shell("sudo snap install " + snap)
self.unit.status = MaintenanceStatus("Setting default display manager")
shell("echo /usr/sbin/lightdm | sudo tee /etc/X11/default-display-manager")
self.unit.status = MaintenanceStatus("Adding XRDP to ssl-cert group")
shell("sudo adduser xrdp ssl-cert")
self.unit.status = MaintenanceStatus("Generating Window Manager startup script")
with open(STARTWM_TEMPLATE, "r") as template:
content = Template(template.read()).render(command=WM_COMMAND)
with open(STARTWM_PATH, "w") as startwm:
startwm.write(content)
self.unit.status = MaintenanceStatus("Generating Polkit files")
with open(POLKIT_TEMPLATE, "r") as template:
content = Template(template.read()).render()
with open(POLKIT_PATH, "w") as polkit:
polkit.write(content)
self._stored.installed = True
def _on_start(self, _):
self.unit.status = MaintenanceStatus("Starting XRDP server")
service_restart('xrdp')
self._stored.started = True
self.unit.status = self._get_current_status()
def _on_stop(self, _):
service_stop('xrdp')
self._stored.started = False
self.unit.status = self._get_current_status()
def _on_config_changed(self, _):
self.unit.status = self._get_current_status()
def _on_update_status(self, _):
self.unit.status = self._get_current_status()
# Action hooks
# Relation hooks
# Private functions
def _get_current_status(self):
status_type = ActiveStatus
status_msg = ""
if self._stored.installed:
status_msg = "Ready"
return status_type(status_msg)
if __name__ == "__main__":
main(VirtualPCCharm)
from apt.progress.base import InstallProgress
from utils import (
install_apt,
)
class Progress(InstallProgress):
def status_change(self, pkg, percent, status):
print("status change\n")
#print(str(int(percent)) + "% \n")
True
if __name__ == "__main__":
install_apt(packages=["mate-backgrounds"], update=True, progress=Progress())
import apt
from apt.progress.base import OpProgress
import shutil
import subprocess
from typing import Dict, List, NoReturn
def service_active(service_name: str):
result = subprocess.run(
["systemctl", "is-active", service_name],
stdout=subprocess.PIPE,
encoding="utf-8",
)
return result.stdout == "active\n"
def all_values_set(dictionary: Dict[str, str]) -> bool:
return not any(v is None for v in dictionary.values())
def install_apt(packages: List, update: bool = False, progress=None) -> NoReturn:
cache = apt.cache.Cache()
if update:
cache.update()
cache.open()
for package in packages:
pkg = cache[package]
if not pkg.is_installed:
pkg.mark_install()
cache.commit(install_progress=progress)
def remove_apt(packages: List, update: bool = False) -> NoReturn:
cache = apt.cache.Cache()
if update:
cache.update()
cache.open()
for package in packages:
pkg = cache[package]
if not pkg.is_installed:
pkg.mark_delete()
cache.commit()
def shell(command: str) -> NoReturn:
subprocess.run(command, shell=True).check_returncode()
def copy_files(origin: Dict[str, str], destination: Dict[str, str]) -> NoReturn:
for config, origin_path in origin.items():
destination_path = destination[config]
shutil.copy(origin_path, destination_path)
# Service functions
def _systemctl(action: str, service_name: str) -> NoReturn:
subprocess.run(["systemctl", action, service_name]).check_returncode()
def service_start(service_name: str) -> NoReturn:
_systemctl("start", service_name)
def service_restart(service_name: str) -> NoReturn:
_systemctl("restart", service_name)
def service_stop(service_name: str) -> NoReturn:
_systemctl("stop", service_name)
def service_enable(service_name: str) -> NoReturn:
_systemctl("enable", service_name)
def systemctl_daemon_reload():
subprocess.run(["systemctl", "daemon-reload"]).check_returncode()
[Allow colord for all users]
Identity=unix-user:*
Action=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile
ResultAny=yes
ResultInactive=yes
ResultActive=yes
\ No newline at end of file
#!/bin/sh
# xrdp X session start script (c) 2015, 2017 mirabilos
# published under The MirOS Licence
if test -r /etc/profile; then
. /etc/profile
fi
if test -r /etc/default/locale; then
. /etc/default/locale
test -z "${LANG+x}" || export LANG
test -z "${LANGUAGE+x}" || export LANGUAGE
test -z "${LC_ADDRESS+x}" || export LC_ADDRESS
test -z "${LC_ALL+x}" || export LC_ALL
test -z "${LC_COLLATE+x}" || export LC_COLLATE
test -z "${LC_CTYPE+x}" || export LC_CTYPE
test -z "${LC_IDENTIFICATION+x}" || export LC_IDENTIFICATION
test -z "${LC_MEASUREMENT+x}" || export LC_MEASUREMENT
test -z "${LC_MESSAGES+x}" || export LC_MESSAGES
test -z "${LC_MONETARY+x}" || export LC_MONETARY
test -z "${LC_NAME+x}" || export LC_NAME
test -z "${LC_NUMERIC+x}" || export LC_NUMERIC
test -z "${LC_PAPER+x}" || export LC_PAPER
test -z "${LC_TELEPHONE+x}" || export LC_TELEPHONE
test -z "${LC_TIME+x}" || export LC_TIME
test -z "${LOCPATH+x}" || export LOCPATH
fi
if test -r /etc/profile; then
. /etc/profile
fi
{{ command }}
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
import unittest
from unittest.mock import Mock
from ops.testing import Harness
from charm import SrsLteCharm
class TestCharm(unittest.TestCase):
def test_config_changed(self):
harness = Harness(SrsLteCharm)
self.addCleanup(harness.cleanup)
harness.begin()
self.assertEqual(list(harness.charm._stored.things), [])
harness.update_config({"thing": "foo"})
self.assertEqual(list(harness.charm._stored.things), ["foo"])
def test_action(self):
harness = Harness(SrsLteCharm)
harness.begin()
# the harness doesn't (yet!) help much with actions themselves
action_event = Mock(params={"fail": ""})
harness.charm._on_fortune_action(action_event)
self.assertTrue(action_event.set_results.called)
def test_action_fail(self):
harness = Harness(SrsLteCharm)
harness.begin()
action_event = Mock(params={"fail": "fail this"})
harness.charm._on_fortune_action(action_event)
self.assertEqual(action_event.fail.call_args, [("fail this",)])
This diff is collapsed.
# virtual-pc
## Description
## Usage
### Prepare the environment
```bash
sudo snap install juju --classic --channel 2.8/stable
sudo snap install lxd
lxd.init
juju bootstrap lxd
juju add-model test-virtual-pc
```
### Deploy (from the Store)
```bash
juju deploy cs:~charmed-osm/virtual-pc --channel edge
```
### Deploy (locally)
Build the charm:
```bash
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
pip install charmcraft
./venv/bin/charmcraft build
```
Deploy:
```bash
juju deploy ./virtual-pc.charm
```
## Developing
Create and activate a virtualenv with the development requirements:
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
## Testing
The Python operator framework includes a very nice harness for testing
operator behaviour without full deployment. Just `run_tests`:
./run_tests
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment