Skip to content

Commit

Permalink
landscape: support enabling and disabling landscape-client
Browse files Browse the repository at this point in the history
  • Loading branch information
orndorffgrant committed Jul 20, 2023
1 parent 4996286 commit 4f70bb1
Show file tree
Hide file tree
Showing 14 changed files with 598 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ jobs:
UACLIENT_BEHAVE_CONTRACT_TOKEN: '${{ secrets.UACLIENT_BEHAVE_CONTRACT_TOKEN }}'
UACLIENT_BEHAVE_CONTRACT_TOKEN_STAGING: '${{ secrets.UACLIENT_BEHAVE_CONTRACT_TOKEN_STAGING }}'
UACLIENT_BEHAVE_CONTRACT_TOKEN_STAGING_EXPIRED: '${{ secrets.UACLIENT_BEHAVE_CONTRACT_TOKEN_STAGING_EXPIRED }}'
UACLIENT_BEHAVE_LANDSCAPE_REGISTRATION_KEY: '${{ secrets.UACLIENT_BEHAVE_LANDSCAPE_REGISTRATION_KEY }}'
UACLIENT_BEHAVE_LANDSCAPE_API_ACCESS_KEY: '${{ secrets.UACLIENT_BEHAVE_LANDSCAPE_API_ACCESS_KEY }}'
UACLIENT_BEHAVE_LANDSCAPE_API_SECRET_KEY: '${{ secrets.UACLIENT_BEHAVE_LANDSCAPE_API_SECRET_KEY }}'
run: |
PYCLOUDLIB_CONFIG="$(mktemp --tmpdir="${{ runner.temp }}" pycloudlib.toml.XXXXXXXXXX)"
GCE_CREDENTIALS_PATH="$(mktemp --tmpdir="${{ runner.temp }}" gcloud.json.XXXXXXXXXX)"
Expand Down
12 changes: 12 additions & 0 deletions features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ class UAClientBehaveConfig:
"contract_token",
"contract_token_staging",
"contract_token_staging_expired",
"landscape_registration_key",
"landscape_api_access_key",
"landscape_api_secret_key",
"machine_type",
"private_key_file",
"private_key_name",
Expand All @@ -102,6 +105,9 @@ class UAClientBehaveConfig:
"contract_token",
"contract_token_staging",
"contract_token_staging_expired",
"landscape_registration_key",
"landscape_api_access_key",
"landscape_api_secret_key",
]

# This variable is used in .from_environ() but also to emit the "Config
Expand All @@ -124,6 +130,9 @@ def __init__(
contract_token: Optional[str] = None,
contract_token_staging: Optional[str] = None,
contract_token_staging_expired: Optional[str] = None,
landscape_registration_key: Optional[str] = None,
landscape_api_access_key: Optional[str] = None,
landscape_api_secret_key: Optional[str] = None,
artifact_dir: str = "artifacts",
install_from: InstallationSource = InstallationSource.LOCAL,
custom_ppa: Optional[str] = None,
Expand All @@ -141,6 +150,9 @@ def __init__(
self.contract_token = contract_token
self.contract_token_staging = contract_token_staging
self.contract_token_staging_expired = contract_token_staging_expired
self.landscape_registration_key = landscape_registration_key
self.landscape_api_access_key = landscape_api_access_key
self.landscape_api_secret_key = landscape_api_secret_key
self.image_clean = image_clean
self.destroy_instances = destroy_instances
self.machine_type = machine_type
Expand Down
247 changes: 247 additions & 0 deletions features/landscape.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
@uses.config.contract_token
@uses.config.landscape_registration_key
@uses.config.landscape_api_access_key
@uses.config.landscape_api_secret_key
Feature: Enable landscape on Ubuntu

@series.lunar
@uses.config.machine_type.any
@uses.config.machine_type.lxd-container
Scenario Outline: Enable Landscape non-interactively
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed
When I set the machine token overlay to the following yaml
"""
availableResources:
- available: true
name: landscape
machineTokenInfo:
contractInfo:
resourceEntitlements:
- type: landscape
affordances:
series:
- focal
- jammy
- kinetic
- lunar
- mantic
"""
When I attach `contract_token` with sudo and options `--no-auto-enable`

Then I verify that running `pro enable landscape` `as non-root` exits `1`
And I will see the following on stderr:
"""
This command must be run as root (try using sudo).
"""

When I run `pro enable landscape -- --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --registration-key $behave_var{config landscape_registration_key} --silent` with sudo
Then stdout contains substring:
"""
One moment, checking your subscription first
Updating package lists
Installing landscape-client
Executing `landscape-config --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --registration-key <REDACTED> --silent`
"""
Then stdout contains substring
"""
Landscape enabled
"""
When I run `pro status` as non-root
Then stdout matches regexp:
"""
landscape +yes +enabled
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +enabled
"""

When I run `systemctl stop landscape-client` with sudo
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +warning
"""
Then stdout contains substring:
"""
Landscape is installed and configured and registered but not running.
Run `sudo landscape-config` to start it, or run `sudo pro disable landscape`
"""

When I run `rm /etc/landscape/client.conf` with sudo
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +warning
"""
Then stdout contains substring:
"""
Landscape is installed but not configured.
Run `sudo landscape-config` to set it up, or run `sudo pro disable landscape`
"""

When I run `sudo pro disable landscape` with sudo
Then I will see the following on stdout:
"""
Executing `landscape-config --disable`
Failed running command 'landscape-config --disable' [exit(1)]. Message: error: config file /etc/landscape/client.conf can't be read
Backing up /etc/landscape/client.conf as /etc/landscape/client.conf.pro-disable-backup
[Errno 2] No such file or directory: '/etc/landscape/client.conf' -> '/etc/landscape/client.conf.pro-disable-backup'
Uninstalling landscape-client
Landscape disabled
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +disabled
"""

# Enable with assume-yes
When I run `pro enable landscape --assume-yes -- --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --registration-key $behave_var{config landscape_registration_key}` with sudo
Then I will see the following on stdout:
"""
One moment, checking your subscription first
Updating package lists
Installing landscape-client
Executing `landscape-config --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --registration-key <REDACTED> --silent`
Landscape enabled
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +enabled
"""
When I run `sudo pro disable landscape` with sudo

# Fail to enable with assume-yes
When I verify that running `pro enable landscape --assume-yes -- --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa` `with sudo` exits `1`
Then I will see the following on stdout:
"""
One moment, checking your subscription first
Updating package lists
Installing landscape-client
Executing `landscape-config --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --silent`
Created symlink /etc/systemd/system/multi-user.target.wants/landscape-client.service → /lib/systemd/system/landscape-client.service.
Invalid account name or registration key.
Could not enable Landscape.
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +warning
"""
Then stdout contains substring:
"""
Landscape is installed and configured but not registered.
Run `sudo landscape-config` to register, or run `sudo pro disable landscape`
"""
When I run `sudo pro disable landscape` with sudo

# Enable with assume-yes and format json
When I run `pro enable landscape --assume-yes --format=json -- --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa --registration-key $behave_var{config landscape_registration_key}` with sudo
Then I will see the following on stdout:
"""
{"_schema_version": "0.1", "errors": [], "failed_services": [], "needs_reboot": false, "processed_services": ["landscape"], "result": "success", "warnings": []}
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +enabled
"""
When I run `sudo pro disable landscape` with sudo

# Fail to enable with assume-yes and format json
When I verify that running `pro enable landscape --assume-yes --format=json -- --computer-title $behave_var{machine-name system-under-test} --account-name pro-client-qa` `with sudo` exits `1`
Then I will see the following on stdout:
"""
{"_schema_version": "0.1", "errors": [{"additional_info": {"stderr": "Created symlink /etc/systemd/system/multi-user.target.wants/landscape-client.service \u2192 /lib/systemd/system/landscape-client.service.\nInvalid account name or registration key.", "stdout": "Please wait..."}, "message": "landscape-config command failed", "message_code": "landscape-config-failed", "service": "landscape", "type": "service"}], "failed_services": ["landscape"], "needs_reboot": false, "processed_services": [], "result": "failure", "warnings": []}
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +warning
"""
Then stdout contains substring:
"""
Landscape is installed and configured but not registered.
Run `sudo landscape-config` to register, or run `sudo pro disable landscape`
"""
When I run `sudo pro disable landscape` with sudo

# cleanup
Then I reject all pending computers on Landscape
Examples: ubuntu release
| release | machine_type |
| lunar | lxd-container |

@series.lunar
@uses.config.machine_type.any
@uses.config.machine_type.lxd-container
Scenario Outline: Enable Landscape interactively
Given a `<release>` `<machine_type>` machine with ubuntu-advantage-tools installed
When I set the machine token overlay to the following yaml
"""
availableResources:
- available: true
name: landscape
machineTokenInfo:
contractInfo:
resourceEntitlements:
- type: landscape
affordances:
series:
- focal
- jammy
- kinetic
- lunar
- mantic
"""
When I attach `contract_token` with sudo and options `--no-auto-enable`

Then I verify that running `pro enable landscape` `as non-root` exits `1`
And I will see the following on stderr:
"""
This command must be run as root (try using sudo).
"""

When I run `pro enable landscape` `with sudo` and the following stdin
"""
y
$behave_var{machine-name system-under-test}
pro-client-qa
$behave_var{config landscape_registration_key}
$behave_var{config landscape_registration_key}
n
y
"""
Then stdout contains substring:
"""
One moment, checking your subscription first
Updating package lists
Installing landscape-client
Executing `landscape-config`
"""
Then stdout contains substring:
"""
System successfully registered.
"""
Then stdout contains substring
"""
Landscape enabled
"""
When I run `pro status` with sudo
Then stdout matches regexp:
"""
landscape +yes +enabled
"""

# cleanup
Then I reject all pending computers on Landscape
Examples: ubuntu release
| release | machine_type |
| lunar | lxd-container |
69 changes: 69 additions & 0 deletions features/steps/landscape.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import hmac
import json
import time
from base64 import b64encode
from hashlib import sha256
from urllib.parse import quote
from urllib.request import Request, urlopen

from behave import step


def _landscape_api_request(access_key, secret_key, action, action_params):
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
params = {
"action": action,
"access_key_id": access_key,
"signature_method": "HmacSHA256",
"signature_version": "2",
"timestamp": timestamp,
"version": "2011-08-01",
**action_params,
}
method = "POST"
uri = "https://landscape.canonical.com/api/"
host = "landscape.canonical.com"
path = "/api/"

formatted_params = "&".join(
quote(k, safe="~") + "=" + quote(v, safe="~")
for k, v in sorted(params.items())
)

to_sign = "{method}\n{host}\n{path}\n{formatted_params}".format(
method=method,
host=host,
path=path,
formatted_params=formatted_params,
)
digest = hmac.new(secret_key.encode(), to_sign.encode(), sha256).digest()
signature = b64encode(digest)
formatted_params += "&signature=" + quote(signature)

request = Request(
uri,
headers={"Host": host},
method=method,
data=formatted_params.encode(),
)
response = urlopen(request)

return response.code, json.load(response)


@step("I reject all pending computers on Landscape")
def reject_all_pending_computers(context):
access_key = context.pro_config.landscape_api_access_key
secret_key = context.pro_config.landscape_api_secret_key
code, pending_computers = _landscape_api_request(
access_key, secret_key, "GetPendingComputers", {}
)
assert code == 200
reject_params = {
"computer_ids.{}".format(i + 1): str(computer["id"])
for i, computer in enumerate(pending_computers)
}
code, _resp = _landscape_api_request(
access_key, secret_key, "RejectPendingComputers", reject_params
)
assert code == 200
6 changes: 6 additions & 0 deletions help_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ fips-updates:
for those modules that have been provided since their certification date.
You can find out more at https://ubuntu.com/security/certifications#fips.
landscape:
help: |
landscape is a ... TODO
Find out more about Landscape at
https://ubuntu.com/landscape
livepatch:
help: |
Livepatch provides selected high and critical kernel CVE fixes and other
Expand Down
4 changes: 2 additions & 2 deletions tools/ua.bash
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ _ua_complete()
prev_word="${COMP_WORDS[COMP_CWORD-1]}"

if [ "$VERSION_ID" = "16.04" ] || [ "$VERSION_ID" == "18.04" ]; then
services="cc-eal cis esm-apps esm-infra fips fips-updates livepatch realtime-kernel ros ros-updates"
services="cc-eal cis esm-apps esm-infra fips fips-updates landscape livepatch realtime-kernel ros ros-updates"
else
services="cc-eal esm-apps esm-infra fips fips-updates livepatch realtime-kernel ros ros-updates usg"
services="cc-eal esm-apps esm-infra fips fips-updates landscape livepatch realtime-kernel ros ros-updates usg"
fi

subcmds="--debug --help --version api attach auto-attach collect-logs config detach disable enable fix help refresh security-status status system version"
Expand Down
Loading

0 comments on commit 4f70bb1

Please sign in to comment.