Skip to content

Commit

Permalink
daemon: auto-attach when pro license added on gcp
Browse files Browse the repository at this point in the history
  • Loading branch information
orndorffgrant committed Feb 4, 2022
1 parent dc131c2 commit 8b32e1c
Show file tree
Hide file tree
Showing 29 changed files with 773 additions and 13 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,19 @@ by a string formatted as:

`<protocol>://[<username>:<password>@]<fqdn>:<port>`

### Pro Upgrade Daemon
UA client sets up a daemon on supported platforms (currently GCP only) to
detect if an Ubuntu Pro license is purchased for the machine. If a Pro license
is detected, then the machine is automatically attached.

If you are uninterested in UA services, you can safely stop and disable the
daemon using systemctl:

```
sudo systemctl stop ubuntu-advantage.service
sudo systemctl disable ubuntu-advantage.service
```

### Timer jobs
UA client sets up a systemd timer to run jobs that need to be executed recurrently.
The timer itself ticks every 5 minutes on average, and decides which jobs need
Expand Down
2 changes: 2 additions & 0 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ override_dh_systemd_enable:
dh_systemd_enable -pubuntu-advantage-tools ua-license-check.timer
dh_systemd_enable -pubuntu-advantage-tools ua-license-check.service
dh_systemd_enable -pubuntu-advantage-tools ua-license-check.path
dh_systemd_enable -pubuntu-advantage-tools ubuntu-advantage.service

override_dh_systemd_start:
dh_systemd_start -pubuntu-advantage-tools ua-timer.timer
dh_systemd_start -pubuntu-advantage-tools ua-license-check.path
dh_systemd_start -pubuntu-advantage-tools ubuntu-advantage.service

override_dh_auto_install:
dh_auto_install --destdir=debian/ubuntu-advantage-tools
Expand Down
1 change: 1 addition & 0 deletions debian/ubuntu-advantage-tools.postrm
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ remove_logs(){
rm -f /var/log/ubuntu-advantage.log*
rm -f /var/log/ubuntu-advantage-timer.log*
rm -f /var/log/ubuntu-advantage-license-check.log*
rm -f /var/log/ubuntu-advantage-daemon.log*
}

remove_gpg_files(){
Expand Down
4 changes: 4 additions & 0 deletions features/attached_commands.feature
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ Feature: Command behaviour when attached to an UA subscription
And I run `sh -c "ls /var/log/ubuntu-advantage* | sort -d"` as non-root
Then stdout matches regexp:
"""
/var/log/ubuntu-advantage-daemon.log
/var/log/ubuntu-advantage.log
/var/log/ubuntu-advantage-timer.log
"""
When I run `logrotate --force /etc/logrotate.d/ubuntu-advantage-tools` with sudo
And I run `sh -c "ls /var/log/ubuntu-advantage* | sort -d"` as non-root
Then stdout matches regexp:
"""
/var/log/ubuntu-advantage-daemon.log.1
/var/log/ubuntu-advantage.log.1
/var/log/ubuntu-advantage-timer.log.1
"""
Expand Down Expand Up @@ -837,7 +839,9 @@ Feature: Command behaviour when attached to an UA subscription
ua-status.json
ua-timer.service.txt
ua-timer.timer.txt
ubuntu-advantage-daemon.log
ubuntu-advantage.log
ubuntu-advantage.service.txt
ubuntu-advantage-timer.log
ubuntu-esm-apps.list
ubuntu-esm-infra.list
Expand Down
37 changes: 37 additions & 0 deletions features/daemon.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Feature: UA daemon starts and stops jobs appropriately

# TODO: Replace this as soon as the daemon does something real
@series.all
@uses.config.machine_type.lxd.container
Scenario Outline: Check daemon starts and restarts
Given a `<release>` machine with ubuntu-advantage-tools installed
Then I verify that running `systemctl status ubuntu-advantage.service` `with sudo` exits `3`
Then stdout matches regexp:
"""
code=exited, status=0/SUCCESS
"""
When I run `cat /var/log/ubuntu-advantage-daemon.log` with sudo
Then stdout matches regexp:
"""
daemon started
"""
When I run `truncate -s 0 /var/log/ubuntu-advantage-daemon.log` with sudo
When I run `systemctl restart ubuntu-advantage.service` with sudo
When I wait `1` seconds
Then I verify that running `systemctl status ubuntu-advantage.service` `with sudo` exits `3`
Then stdout matches regexp:
"""
code=exited, status=0/SUCCESS
"""
When I run `cat /var/log/ubuntu-advantage-daemon.log` with sudo
Then stdout matches regexp:
"""
daemon started
"""
Examples: version
| release |
| xenial |
| bionic |
| focal |
| hirsute |
| impish |
10 changes: 6 additions & 4 deletions features/unattached_commands.feature
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ Feature: Command behaviour when unattached

@series.all
@uses.config.machine_type.lxd.container
Scenario Outline: Run collect-logs on an attached machine
Scenario Outline: Run collect-logs on an unattached machine
Given a `<release>` machine with ubuntu-advantage-tools installed
When I run `python3 /usr/lib/ubuntu-advantage/timer.py` with sudo
And I verify that running `ua collect-logs` `as non-root` exits `1`
Expand All @@ -500,7 +500,7 @@ Feature: Command behaviour when unattached
Then I verify that files exist matching `ua_logs.tar.gz`
When I run `tar zxf ua_logs.tar.gz` as non-root
Then I verify that files exist matching `logs/`
When I run `ls -1 logs/` as non-root
When I run `sh -c "ls -1 logs/ | sort -d"` as non-root
Then stdout matches regexp:
"""
build.info
Expand All @@ -511,16 +511,18 @@ Feature: Command behaviour when unattached
systemd-timers.txt
ua-auto-attach.path.txt-error
ua-auto-attach.service.txt-error
uaclient.conf
ua-license-check.path.txt
ua-license-check.service.txt
ua-license-check.timer.txt
ua-reboot-cmds.service.txt
ua-status.json
ua-timer.service.txt
ua-timer.timer.txt
uaclient.conf
ubuntu-advantage-timer.log
ubuntu-advantage.service.txt
ubuntu-advantage-daemon.log
ubuntu-advantage.log
ubuntu-advantage-timer.log
"""
Examples: ubuntu release
| release |
Expand Down
39 changes: 39 additions & 0 deletions lib/daemon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import logging
import sys

from systemd.daemon import notify # type: ignore

from uaclient import daemon
from uaclient.cli import setup_logging
from uaclient.config import UAConfig

LOG = logging.getLogger("ua")


def main() -> int:

cfg = UAConfig()
setup_logging(
logging.INFO, logging.DEBUG, log_file=cfg.daemon_log_file, logger=LOG
)
# The ua-daemon logger should log everything to its file
# Make sure the ua-daemon logger does not generate double logging
# by propagating to the root logger
LOG.propagate = False
# The root logger should only log errors to the daemon log file
setup_logging(
logging.CRITICAL, logging.ERROR, log_file=cfg.daemon_log_file
)

LOG.debug("daemon starting")

notify("READY=1")

daemon.poll_for_pro_license(cfg)

LOG.debug("daemon ending")
return 0


if __name__ == "__main__":
sys.exit(main())
83 changes: 83 additions & 0 deletions sru/release-27.7/gcp_auto_attach_long_poll.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/bin/sh
deb=$1
ZONE="us-east1-b"
INSTANCE_NAME="test-auto-attach"
INSTANCE_TYPE="n1-standard-1"
DISK_NAME="persistent-disk-0"

set -e

GREEN="\e[32m"
RED="\e[31m"
BLUE="\e[36m"
END_COLOR="\e[0m"

function cleanup {
gcloud compute ssh $INSTANCE_NAME -- "sudo ua detach --assume-yes || true"
gcloud compute instances delete $INSTANCE_NAME
}

function on_err {
echo -e "${RED}Test Failed${END_COLOR}"
cleanup
exit 1
}

trap on_err ERR

function print_and_run_cmd {
echo -e "${BLUE}Running:${END_COLOR}" "$@"
echo -e "${BLUE}Output:${END_COLOR}"
gcloud compute ssh $INSTANCE_NAME -- "sh -c \"$@\""
echo
}

function explanatory_message {
echo -e "${BLUE}$@${END_COLOR}"
}

explanatory_message "Starting gcloud instance"
gcloud compute instances create $INSTANCE_NAME \
--image="ubuntu-1604-xenial-v20210429" \
--image-project="ubuntu-os-cloud" \
--machine-type=$INSTANCE_TYPE \
--zone=$ZONE
sleep 30

explanatory_message "Installing new version of ubuntu-advantage-tools from local copy"
gcloud compute scp $deb $INSTANCE_NAME:/tmp/ubuntu-advantage-tools.deb
gcloud compute ssh $INSTANCE_NAME -- "sudo apt update"
gcloud compute ssh $INSTANCE_NAME -- "sudo apt install ubuntu-advantage-tools -y"
print_and_run_cmd "sudo dpkg -i /tmp/ubuntu-advantage-tools.deb"
explanatory_message "skip initial license check"
print_and_run_cmd "sudo sed -zi \\\"s/cloud.is_pro_license_present(\n wait_for_change=False\n )/False/\\\" /usr/lib/python3/dist-packages/uaclient/daemon.py"
explanatory_message "turn on polling in config file"
print_and_run_cmd "sudo sh -c \\\"printf \\\\\\\" poll_for_pro_license: true\\\\\\\" >> /etc/ubuntu-advantage/uaclient.conf\\\""
explanatory_message "change won't happen while daemon is running, so set short timeout to simulate the long poll returning"
print_and_run_cmd "sudo sed -i \\\"s/wait_for_change=true/wait_for_change=true\&timeout_sec=5/\\\" /usr/lib/python3/dist-packages/uaclient/clouds/gcp.py"

gcloud compute ssh $INSTANCE_NAME -- "sudo touch /run/cloud-init/cloud-id-gce" # feature not in cloud-init yet
gcloud compute ssh $INSTANCE_NAME -- "sudo systemctl restart ubuntu-advantage.service"
explanatory_message "Checking the status and logs beforehand"
print_and_run_cmd "sudo ua status --wait"
print_and_run_cmd "sudo cat /var/log/ubuntu-advantage-daemon.log"

explanatory_message "Stopping the machine, adding license, restarting..."
gcloud compute instances stop $INSTANCE_NAME
gcloud beta compute disks update $INSTANCE_NAME --zone=$ZONE --update-user-licenses="https://www.googleapis.com/compute/v1/projects/ubuntu-os-pro-cloud/global/licenses/ubuntu-pro-1604-lts"
gcloud compute instances start $INSTANCE_NAME
sleep 30

gcloud compute ssh $INSTANCE_NAME -- "sudo truncate -s 0 /var/log/ubuntu-advantage-daemon.log"
gcloud compute ssh $INSTANCE_NAME -- "sudo touch /run/cloud-init/cloud-id-gce" # feature not in cloud-init yet
gcloud compute ssh $INSTANCE_NAME -- "sudo systemctl restart ubuntu-advantage.service"
sleep 10

explanatory_message "Now with the license, it will succeed auto_attaching"
print_and_run_cmd "sudo ua status --wait"
print_and_run_cmd "sudo cat /var/log/ubuntu-advantage-daemon.log"
result=$(gcloud compute ssh $INSTANCE_NAME -- "sudo ua status --format json")
echo $result | jq -r ".attached" | grep "true"

echo -e "${GREEN}Test Passed${END_COLOR}"
cleanup
76 changes: 76 additions & 0 deletions sru/release-27.7/gcp_auto_attach_on_boot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/bin/sh
deb=$1
ZONE="us-east1-b"
INSTANCE_NAME="test-auto-attach"
INSTANCE_TYPE="n1-standard-1"
DISK_NAME="persistent-disk-0"

set -e

GREEN="\e[32m"
RED="\e[31m"
BLUE="\e[36m"
END_COLOR="\e[0m"

function cleanup {
gcloud compute ssh $INSTANCE_NAME -- "sudo ua detach --assume-yes || true"
gcloud compute instances delete $INSTANCE_NAME
}

function on_err {
echo -e "${RED}Test Failed${END_COLOR}"
cleanup
exit 1
}

trap on_err ERR

function print_and_run_cmd {
echo -e "${BLUE}Running:${END_COLOR}" "$@"
echo -e "${BLUE}Output:${END_COLOR}"
gcloud compute ssh $INSTANCE_NAME -- "sh -c \"$@\""
echo
}

function explanatory_message {
echo -e "${BLUE}$@${END_COLOR}"
}

explanatory_message "Starting gcloud instance"
gcloud compute instances create $INSTANCE_NAME \
--image="ubuntu-1604-xenial-v20210429" \
--image-project="ubuntu-os-cloud" \
--machine-type=$INSTANCE_TYPE \
--zone=$ZONE
sleep 30


explanatory_message "Installing new version of ubuntu-advantage-tools from local copy"
gcloud compute scp $deb $INSTANCE_NAME:/tmp/ubuntu-advantage-tools.deb
gcloud compute ssh $INSTANCE_NAME -- "sudo apt update"
gcloud compute ssh $INSTANCE_NAME -- "sudo apt install ubuntu-advantage-tools jq -y"
print_and_run_cmd "sudo dpkg -i /tmp/ubuntu-advantage-tools.deb"
explanatory_message "turn on polling in config file"
gcloud compute ssh $INSTANCE_NAME -- "sudo touch /run/cloud-init/cloud-id-gce" # feature not in cloud-init yet
gcloud compute ssh $INSTANCE_NAME -- "sudo systemctl restart ubuntu-advantage.service"
explanatory_message "Checking the status and logs beforehand"
print_and_run_cmd "sudo ua status --wait"
print_and_run_cmd "sudo cat /var/log/ubuntu-advantage-daemon.log"

explanatory_message "Stopping the machine, adding license, restarting..."
gcloud compute instances stop $INSTANCE_NAME
gcloud beta compute disks update $INSTANCE_NAME --zone=$ZONE --update-user-licenses="https://www.googleapis.com/compute/v1/projects/ubuntu-os-pro-cloud/global/licenses/ubuntu-pro-1604-lts"
gcloud compute instances start $INSTANCE_NAME
sleep 30

print_and_run_cmd "sudo truncate -s 0 /var/log/ubuntu-advantage-daemon.log"
gcloud compute ssh $INSTANCE_NAME -- "sudo touch /run/cloud-init/cloud-id-gce" # feature not in cloud-init yet
gcloud compute ssh $INSTANCE_NAME -- "sudo systemctl restart ubuntu-advantage.service"
explanatory_message "Now with the license, it will succeed auto_attaching on boot"
print_and_run_cmd "sudo ua status --wait"
print_and_run_cmd "sudo cat /var/log/ubuntu-advantage-daemon.log"
result=$(gcloud compute ssh $INSTANCE_NAME -- "sudo ua status --format json")
echo $result | jq -r ".attached" | grep "true"

echo -e "${GREEN}Test Passed${END_COLOR}"
cleanup
25 changes: 25 additions & 0 deletions systemd/ubuntu-advantage.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# If you are uninterested in the (free for personal use) Ubuntu Advantage
# services, including security updates after standard EOL and kernel patching
# without rebooting, then you can safely stop and disable this service:
# sudo systemctl stop ubuntu-advantage.service
# sudo systemctl disable ubuntu-advantage.service

[Unit]
Description=Ubuntu Advantage GCP Auto Attach Daemon
Documentation=man:ubuntu-advantage https://ubuntu.com/advantage
After=network.target network-online.target systemd-networkd.service ua-auto-attach.service cloud-config.target

# Only run if not already attached
ConditionPathExists=!/var/lib/ubuntu-advantage/private/machine-token.json
# Only run on GCP
ConditionPathExists=/run/cloud-init/cloud-id-gce

[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/bin/python3 /usr/lib/ubuntu-advantage/daemon.py
Restart=on-failure
WorkingDirectory=/var/lib/ubuntu-advantage/

[Install]
WantedBy=multi-user.target
1 change: 1 addition & 0 deletions uaclient-devel.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ log_level: debug
security_url: https://ubuntu.com/security
timer_log_file: ubuntu-advantage-timer-devel.log
license_check_log_file: ubuntu-advantage-license-check-devel.log
daemon_log_file: ubuntu-advantage-daemon-devel.log
ua_config:
apt_http_proxy: null
apt_https_proxy: null
Expand Down
1 change: 1 addition & 0 deletions uaclient.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ log_file: /var/log/ubuntu-advantage.log
log_level: debug
security_url: https://ubuntu.com/security
timer_log_file: /var/log/ubuntu-advantage-timer.log
daemon_log_file: /var/log/ubuntu-advantage-daemon.log
ua_config:
apt_http_proxy: null
apt_https_proxy: null
Expand Down
Loading

0 comments on commit 8b32e1c

Please sign in to comment.