-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: How-to create WSL instances on multiple Windows machines via La…
…ndscape API (#928) This PR makes heavy use of tabbed code blocks to show alternative ways to do things with Bash and PowerShell. ![image](https://github.com/user-attachments/assets/a35f3c82-2094-404d-8a68-f13a3c2ccf6c) Both alternatives were tested. The bash one comes from the [Landscape documentation](https://ubuntu.com/landscape/docs/use-a-specific-ubuntu-image-source-for-wsl#installing-with-a-custom-image), I essentially extracted the piece I was more concerned about (custom rootfs with cloud-init data) and made a self-contained guide out of it (plus translating to PowerShell). --- UDENG-4694
- Loading branch information
Showing
7 changed files
with
330 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,10 +48,12 @@ fpath | |
FQDN | ||
HIPAA | ||
Hostagent | ||
JWT | ||
LTS | ||
os | ||
pem | ||
repo | ||
rootfs | ||
SLA | ||
SRU | ||
SSL | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
# How-to deploy a custom rootfs across multiple Windows machines with the Landscape API | ||
|
||
This guide shows how to use the Landscape API to automate the deployment of a custom rootfs across multiple Windows machines. | ||
Scaled deployment is enabled by Ubuntu Pro for WSL, which ensures that Ubuntu WSL instances on Windows machines are automatically registered with Landscape. | ||
Cloud-init is used for initialisation and final configuration of the instances. | ||
To follow the steps outlined in this guide you can use either: | ||
- Bash scripting on Linux, or | ||
- PowerShell scripting on Windows | ||
|
||
## Prerequisites | ||
|
||
- A running self-hosted Landscape server version `24.10~beta.5` or later. | ||
- Multiple Windows machines [already registered with Landscape](howto::config-landscape) via Ubuntu Pro for WSL. | ||
- Make sure you have installed `curl` and `jq`, if you're following this guide using Bash. | ||
- Familiarity with Bash and/or PowerShell. | ||
|
||
## Prepare the environment | ||
|
||
For convenience when writing subsequent commands, first export the following environment variables, modifying the values that are assigned as needed: | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
# Credentials to authenticate the API requests | ||
export [email protected] | ||
export LANDSCAPE_USER_PASSWORD=mib | ||
export LANDSCAPE_URL=https://landscape.mib.com | ||
# The URL of the custom rootfs to be deployed | ||
export ROOTFS_URL="http://landscape.mib.com:9009/ubuntu-24.04-custom.tar.gz" | ||
# The list of IDs of the different Windows machines on which we are going to deploy WSL instances | ||
export PARENT_COMPUTER_IDS=(26 30 31) | ||
# The name of the WSL instance to be created | ||
export COMPUTER_NAME=Carbonizer | ||
# Path to the cloud-config file whose contents will be used to initialize the WSL instances | ||
export CLOUD_INIT_FILE="~/Downloads/init.yaml" | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
# Credentials to authenticate the API requests | ||
$LANDSCAPE_USER_EMAIL="[email protected]" | ||
$LANDSCAPE_USER_PASSWORD="mib" | ||
$LANDSCAPE_URL="https://landscape.mib.com" | ||
# The URL of the custom rootfs to be deployed | ||
$ROOTFS_URL="http://landscape.mib.com:9009/ubuntu-24.04-custom.tar.gz" | ||
# The list of IDs of the different Windows machines on which we are going to deploy WSL instances | ||
$PARENT_COMPUTER_IDS=@(26, 30, 31) | ||
# The name of the WSL instance to be created | ||
$COMPUTER_NAME="Carbonizer" | ||
# Path to the cloud-config file whose contents will be used to initialize the WSL instances | ||
$CLOUD_INIT_FILE="~\Downloads\init.yaml" | ||
``` | ||
```` | ||
````` | ||
|
||
|
||
Generate a Base64-encoded string with the cloud-config data: | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
BASE64_ENCODED_CLOUD_INIT=$(cat $CLOUD_INIT_FILE | base64 --wrap=0) | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
$content = Get-Content -Path $CLOUD_INIT_FILE -Raw | ||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($content) | ||
$BASE64_ENCODED_CLOUD_INIT = [System.Convert]::ToBase64String($bytes) | ||
``` | ||
```` | ||
````` | ||
|
||
## Authenticate against the Landscape API | ||
|
||
Build the authentication payload of the form: `{"email": "[email protected]", "password": "mib"}` using the values exported in prior steps: | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
LOGIN_JSON=$( jq -n \ | ||
--arg em "$LANDSCAPE_USER_EMAIL" \ | ||
--arg pwd "$LANDSCAPE_USER_PASSWORD" \ | ||
'{email: $em, password: $pwd}' ) | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
$LOGIN_JSON = @{ | ||
email = "$LANDSCAPE_USER_EMAIL" | ||
password = "$LANDSCAPE_USER_PASSWORD" | ||
} | ConvertTo-Json | ||
``` | ||
```` | ||
````` | ||
|
||
Issue an authenticate request and retrieve the JSON web token (JWT) to be used in the subsequent API requests. | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
LOGIN_RESPONSE=$( curl -s -X POST "$LANDSCAPE_URL/api/v2/login" \ | ||
--data "$LOGIN_JSON" \ | ||
--header "Content-Type: application/json" \ | ||
--header "Accept: application/json" ) | ||
JWT=$( echo $LOGIN_RESPONSE | jq .token | tr -d '"') | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
$LOGIN_RESPONSE = Invoke-WebRequest -Method POST ` | ||
-URI "$LANDSCAPE_URL/api/v2/login" ` | ||
-Body "$LOGIN_JSON" -ContentType "application/json" | ||
$JWT = ConvertTo-SecureString -AsPlainText -Force $( $LOGIN_RESPONSE.Content | ConvertFrom-Json).token | ||
``` | ||
```` | ||
````` | ||
|
||
## Send the Install request | ||
|
||
Build the payload with information about the WSL instance to be deployed. In this case it would look like: | ||
|
||
```json | ||
{"rootfs_url": "http://landscape.mib.com:9009/ubuntu-24.04-custom.tar.gz", "computer_name": "Carbonizer", "cloud_init": "<base64 encoded material>"} | ||
``` | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
WSL_JSON=$( jq -n \ | ||
--arg rf "$ROOTFS_URL" \ | ||
--arg cn "$COMPUTER_NAME" \ | ||
--arg b64 "$BASE64_ENCODED_CLOUD_INIT" \ | ||
'{rootfs_url: $rf, computer_name: $cn, cloud_init: $b64}' ) | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
$WSL_JSON = @{ | ||
rootfs_url = "$ROOTFS_URL" | ||
computer_name = "$COMPUTER_NAME" | ||
cloud_init = "$BASE64_ENCODED_CLOUD_INIT" | ||
} | ConvertTo-Json | ||
``` | ||
```` | ||
````` | ||
|
||
At the moment of this writing there is no specific API endpoint to trigger | ||
installation of WSL instances on multiple Windows machines at once. | ||
Instead we send one request per target machine. | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
for COMPUTER_ID in "${PARENT_COMPUTER_IDS[@]}"; do | ||
API_RESPONSE=$( curl -s -X POST \ | ||
"$LANDSCAPE_URL/api/v2/computers/$COMPUTER_ID/children" \ | ||
--data "$WSL_JSON" \ | ||
--header "Authorization:Bearer $JWT" \ | ||
--header "Content-Type: application/json" \ | ||
--header "Accept: application/json" ) | ||
# show the response | ||
echo $API_RESPONSE | ||
echo | ||
done | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
foreach ($COMPUTER_ID in $PARENT_COMPUTER_IDS) { | ||
$API_RESPONSE = Invoke-WebRequest -Method POST -Body "$WSL_JSON" ` | ||
-Uri "$LANDSCAPE_URL/api/v2/computers/$COMPUTER_ID/children" ` | ||
-Authentication Bearer -Token $JWT -ContentType "application/json" | ||
# show the response | ||
Write-Output $API_RESPONSE | ||
} | ||
``` | ||
```` | ||
````` | ||
|
||
When that completes, you'll be able to find activities in the Landscape | ||
dashboard about the installation of a new WSL instance for each of the Windows | ||
machines listed. | ||
|
||
## Summarising the steps in a single script | ||
|
||
The steps above can be made into a single script: | ||
|
||
`````{tabs} | ||
````{group-tab} Bash | ||
```bash | ||
#!/usr/bin/env bash | ||
# Base64-encoding the cloud-config file contents | ||
BASE64_ENCODED_CLOUD_INIT=$(cat $CLOUD_INIT_FILE | base64 --wrap=0) | ||
# Build the auth payload | ||
LOGIN_JSON=$( jq -n \ | ||
--arg em "$LANDSCAPE_USER_EMAIL" \ | ||
--arg pwd "$LANDSCAPE_USER_PASSWORD" \ | ||
'{email: $em, password: $pwd}' ) | ||
# Issue an auth request and retrieve the JWT | ||
LOGIN_RESPONSE=$( curl -s -X POST "$LANDSCAPE_URL/api/v2/login" \ | ||
--data "$LOGIN_JSON" \ | ||
--header "Content-Type: application/json" \ | ||
--header "Accept: application/json" ) | ||
JWT=$( echo $LOGIN_RESPONSE | jq .token | tr -d '"') | ||
# Build the installation payload | ||
WSL_JSON=$( jq -n \ | ||
--arg rf "$ROOTFS_URL" \ | ||
--arg cn "$COMPUTER_NAME" \ | ||
--arg b64 "$BASE64_ENCODED_CLOUD_INIT" \ | ||
'{rootfs_url: $rf, computer_name: $cn, cloud_init: $b64}' ) | ||
# Issue the command for each Windows machine | ||
for COMPUTER_ID in "${PARENT_COMPUTER_IDS[@]}"; do | ||
API_RESPONSE=$( curl -s -X POST \ | ||
"$LANDSCAPE_URL/api/v2/computers/$COMPUTER_ID/children" \ | ||
--data "$WSL_JSON" \ | ||
--header "Authorization:Bearer $JWT" \ | ||
--header "Content-Type: application/json" \ | ||
--header "Accept: application/json" ) | ||
# show the response | ||
echo $API_RESPONSE | ||
echo | ||
done | ||
``` | ||
```` | ||
````{group-tab} PowerShell | ||
```powershell | ||
# Base64-encoding the cloud-config file contents | ||
$content = Get-Content -Path $CLOUD_INIT_FILE -Raw | ||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($content) | ||
$BASE64_ENCODED_CLOUD_INIT = [System.Convert]::ToBase64String($bytes) | ||
# Build the auth payload | ||
$LOGIN_JSON = @{ | ||
email = "$LANDSCAPE_USER_EMAIL" | ||
password = "$LANDSCAPE_USER_PASSWORD" | ||
} | ConvertTo-Json | ||
# Issue an auth request and retrieve the JWT | ||
$LOGIN_RESPONSE = Invoke-WebRequest -Method POST ` | ||
-URI "$LANDSCAPE_URL/api/v2/login" ` | ||
-Body "$LOGIN_JSON" -ContentType "application/json" | ||
$JWT = ConvertTo-SecureString -AsPlainText -Force $( $LOGIN_RESPONSE.Content | ConvertFrom-Json).token | ||
# Build the installation payload | ||
$WSL_JSON = @{ | ||
rootfs_url = "$ROOTFS_URL" | ||
computer_name = "$COMPUTER_NAME" | ||
cloud_init = "$BASE64_ENCODED_CLOUD_INIT" | ||
} | ConvertTo-Json | ||
# Issue the command for each Windows machine | ||
foreach ($COMPUTER_ID in $PARENT_COMPUTER_IDS) { | ||
$API_RESPONSE = Invoke-WebRequest -Method POST -Body "$WSL_JSON" ` | ||
-Uri "$LANDSCAPE_URL/api/v2/computers/$COMPUTER_ID/children" ` | ||
-Authentication Bearer -Token $JWT -ContentType "application/json" | ||
# show the response | ||
Write-Output $API_RESPONSE | ||
} | ||
``` | ||
```` | ||
````` | ||
|
||
## Further reading | ||
|
||
- Visit [the Landscape API documentation](https://ubuntu.com/landscape/docs/make-rest-api-requests) to learn more about it. | ||
- [Landscape documentation about WSL integration](https://ubuntu.com/landscape/docs/use-a-specific-ubuntu-image-source-for-wsl) | ||
contains more information about this and other methods of creating WSL | ||
instances on Windows machines registered with Landscape via its REST API. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.