Skip to content

Commit a1672dc

Browse files
committed
feat: add module for setting LB backend member weight
1 parent b005d2f commit a1672dc

File tree

15 files changed

+262
-61
lines changed

15 files changed

+262
-61
lines changed

.github/workflows/build-and-release.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ jobs:
2727
run: pip install https://github.com/ansible/ansible/archive/${{env.ANSIBLE_VERSION}}.tar.gz --disable-pip-version-check
2828

2929
- name: Build project release
30-
run: mkdir release && ansible-galaxy collection build --output-path release/
30+
run: |
31+
version=$(grep "version" galaxy.yml | sed -E "s/version:\s+//")
32+
test "${{ github.ref_name }}" = "v$version"
33+
sed -E "s/(VERSION\s+=\s+).*/\1\"$version\"/" -i plugins/module_utils/client.py
34+
mkdir release && ansible-galaxy collection build --output-path release/
3135
3236
- name: Create new release
3337
uses: ncipollo/[email protected]

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Experimental support for managing load balancer backend member weights.
13+
14+
### Changed
15+
16+
- Use `upcloud-ansible-collection` as prefix in the User-Agent header.
17+
1018
## [0.8.1] - 2025-09-04
1119

1220
### Fixed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
variables.yml

examples/inventory-rolling-update/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ Configure a NGINX server with static web page by running the [configure-webserve
2222

2323
```sh
2424
# For initial configuration, configure all targets in parallel
25-
ansible-playbook configure-webserver.yml --extra-vars "serial_override=0"
25+
ansible-playbook configure-webserver.yml --extra-vars "@variables.yml" --extra-vars "serial_override=0"
2626

2727
# When updating the targets, specify which tag (cow, dog, hello, or tiger) to use
28-
ansible-playbook configure-webserver.yml --extra-vars "animal=tiger"
28+
ansible-playbook configure-webserver.yml --extra-vars "@variables.yml" --extra-vars "animal=tiger"
2929
```
3030

3131
To monitor how the rolling update proceeds, open another terminal window and curl the load-balancer URL. The URL is visible at the output of prevous `terraform apply` command and can be printed by running `terraform output`.

examples/inventory-rolling-update/configure-webserver.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66
vars:
77
animal: cow
88
tasks:
9+
- name: Remove from load balancing
10+
upcloud.cloud.loadbalancer_backend_member:
11+
loadbalancer_uuid: "{{ loadbalancer_uuid }}"
12+
backend_name: main
13+
member_name: "member_{{ ansible_facts.hostname[-1:] }}"
14+
weight: 0
15+
when:
16+
- serial_override|default(1)|int != 0
17+
- loadbalancer_uuid is defined
18+
delegate_to: localhost
19+
become: false
920
- name: Install nginx
1021
apt:
1122
package: nginx
@@ -48,6 +59,17 @@
4859
replace: '80'
4960
notify:
5061
- Restart nginx
62+
- name: Add back to load balancing
63+
upcloud.cloud.loadbalancer_backend_member:
64+
loadbalancer_uuid: "{{ loadbalancer_uuid }}"
65+
backend_name: main
66+
member_name: "member_{{ ansible_facts.hostname[-1:] }}"
67+
weight: 100
68+
when:
69+
- serial_override|default(1)|int != 0
70+
- loadbalancer_uuid is defined
71+
delegate_to: localhost
72+
become: false
5173
handlers:
5274
- name: Restart nginx
5375
service:

examples/inventory-rolling-update/resources/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,7 @@ module "load_balancer" {
9393
output "lb_url" {
9494
value = module.load_balancer.dns_name
9595
}
96+
97+
output "lb_uuid" {
98+
value = module.load_balancer.id
99+
}

plugins/inventory/servers.py

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,11 @@
130130
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
131131
from ansible.utils.display import Display
132132

133-
from ..version import collection_version
133+
from ..module_utils.client import initialize_upcloud_client
134134

135135
display = Display()
136136

137137
try:
138-
import upcloud_api
139138
from upcloud_api.errors import UpCloudAPIError
140139
UC_AVAILABLE = True
141140
except ImportError:
@@ -164,37 +163,7 @@ def _initialize_upcloud_client(self):
164163
self.token_env
165164
)
166165

167-
# Token support was added in upcloud-api 2.8.0, older versions will raise TypeError if token is provided.
168-
# Ignore the error if token is not provided, in which case older version should work as well.
169-
try:
170-
credentials = upcloud_api.Credentials.parse(
171-
username=self.username,
172-
password=self.password,
173-
token=self.token,
174-
)
175-
self.client = upcloud_api.CloudManager(**credentials.dict)
176-
except (AttributeError, TypeError):
177-
try:
178-
self.client = upcloud_api.CloudManager(self.username, self.password)
179-
except Exception:
180-
raise AnsibleError(
181-
'Invalid or missing UpCloud API credentials. '
182-
'The version of upcloud-api you are using does not support token authentication or parsing credentials from the environment. '
183-
'Update upcloud-api to version 2.8.0 or later.'
184-
) from None
185-
186-
version = collection_version() or "dev"
187-
self.client.api.user_agent = f"upcloud-ansible-inventory/{version}"
188-
189-
api_root_env = "UPCLOUD_API_ROOT"
190-
if os.getenv(api_root_env):
191-
self.client.api.api_root = os.getenv(api_root_env)
192-
193-
def _test_upcloud_credentials(self):
194-
try:
195-
self.client.authenticate()
196-
except UpCloudAPIError:
197-
raise AnsibleError("Invalid UpCloud API credentials.")
166+
self.client = initialize_upcloud_client(self.username, self.password, self.token)
198167

199168
def _fetch_servers(self):
200169
return self.client.get_servers()
@@ -386,7 +355,6 @@ def verify_file(self, path):
386355

387356
def _populate(self):
388357
self._initialize_upcloud_client()
389-
self._test_upcloud_credentials()
390358
self._get_servers()
391359
self._filter_servers()
392360

plugins/module_utils/__init__.py

Whitespace-only changes.

plugins/module_utils/client.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import os
2+
3+
try:
4+
import upcloud_api
5+
from upcloud_api.errors import UpCloudAPIError
6+
UC_AVAILABLE = True
7+
except ImportError:
8+
UC_AVAILABLE = False
9+
10+
11+
# This value will be replaced in build-and-release workflow
12+
VERSION = "dev"
13+
14+
15+
def initialize_upcloud_client(username=None, password=None, token=None):
16+
if not UC_AVAILABLE:
17+
raise RuntimeError(
18+
"UpCloud Ansible collection requires upcloud-api Python module, "
19+
+ "see https://pypi.org/project/upcloud-api/")
20+
21+
# Token support was added in upcloud-api 2.8.0, older versions will raise TypeError if token is provided.
22+
# Ignore the error if token is not provided, in which case older version should work as well.
23+
try:
24+
credentials = upcloud_api.Credentials.parse(
25+
username=username,
26+
password=password,
27+
token=token,
28+
)
29+
client = upcloud_api.CloudManager(**credentials.dict)
30+
except (AttributeError, TypeError):
31+
try:
32+
client = upcloud_api.CloudManager(username, password)
33+
except Exception:
34+
raise RuntimeError(
35+
'Invalid or missing UpCloud API credentials. '
36+
'The version of upcloud-api you are using does not support token authentication or parsing credentials from the environment. '
37+
'Update upcloud-api to version 2.8.0 or later.'
38+
) from None
39+
40+
version = VERSION
41+
client.api.user_agent = f"upcloud-ansible-collection/{version}"
42+
43+
api_root_env = "UPCLOUD_API_ROOT"
44+
if os.getenv(api_root_env):
45+
client.api.api_root = os.getenv(api_root_env)
46+
47+
try:
48+
client.authenticate()
49+
except UpCloudAPIError:
50+
raise RuntimeError("Invalid UpCloud API credentials.")
51+
52+
return client

plugins/modules/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)