Skip to content

Commit c711f16

Browse files
authored
Merge branch 'rundeck-plugins:master' into master
2 parents 92ca83a + 6c6d94c commit c711f16

13 files changed

Lines changed: 577 additions & 59 deletions

.DS_Store

-8 KB
Binary file not shown.

.github/workflows/gradle.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99

1010
steps:
11-
- uses: actions/checkout@v2
11+
- uses: actions/checkout@v4
1212
with:
1313
fetch-depth: 0
1414
- name: Get Fetch Tags
@@ -24,9 +24,9 @@ jobs:
2424
run: ./gradlew build
2525
- name: Get Release Version
2626
id: get_version
27-
run: VERSION=$(./gradlew currentVersion -q -Prelease.quiet) && echo ::set-output name=VERSION::$VERSION
27+
run: VERSION=$(./gradlew currentVersion -q -Prelease.quiet) && echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
2828
- name: Upload artifact zip
29-
uses: actions/upload-artifact@v1.0.0
29+
uses: actions/upload-artifact@v4.0.0
3030
with:
3131
# Artifact name
3232
name: kubernetes-${{ steps.get_version.outputs.VERSION }}

.github/workflows/snyk-scan.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: Snyk Scan
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
security:
12+
uses: rundeck-plugins/.github/.github/workflows/snyk-scan-reusable.yml@main
13+
secrets:
14+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
15+
SNYK_ORG_ID: ${{ secrets.SNYK_ORG_ID }}

.github/workflows/tests.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: [ '2.x', '3.x' ]
12+
python-version: [ '3.9', '3.10', '3.11', '3.12' ]
1313

1414
steps:
1515
- uses: actions/checkout@v3
@@ -18,7 +18,6 @@ jobs:
1818
with:
1919
python-version: ${{ matrix.python-version }}
2020
architecture: x64
21-
check-latest: true
2221
- name: Install dependencies
2322
run: |
2423
python -m pip install --upgrade pip

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,12 @@ gradle-app.setting
2323

2424
# End of https://www.gitignore.io/api/java,gradle
2525

26+
27+
.DS_Store
28+
29+
# Testing content
30+
.tox
31+
32+
**/__pycache__
33+
34+
/kubernetes_rundeck_plugin.egg-info/*

README.md

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,119 @@ Use cases:
1010

1111
## Requirements
1212

13-
These plugins require the python kubernetes SDK to be installed on the rundeck server.
14-
For example, you can install it using `pip install kubernetes`.
13+
### Python Dependencies
1514

16-
The Python Kubernetes API client requires version 11 of the library. You can confirm it with `python -m pip list | grep kubernetes`.
15+
This plugin requires the following Python packages to be installed **on the server where Rundeck executes** (either your Rundeck server or your Runner nodes if using remote execution):
1716

18-
Further information here: [https://github.com/kubernetes-client/python](https://github.com/kubernetes-client/python).
17+
- **kubernetes** >= 35.0.0 - The official Kubernetes Python client
18+
- **urllib3** >= 2.6.3 - HTTP client library
19+
- **pyyaml** - YAML parser and emitter
20+
- **packaging** >= 20.0 - Version comparison utilities
1921

20-
### Authentication for Tectonic Environments.
21-
There is a pull request [work](https://github.com/kubernetes-client/python-base/pull/48) for the kubernetes python SDK to support authenticating with the kubernetes API using OIDC (which is used by tectonic).
22+
**Installation location:**
23+
- **Rundeck server**: If running jobs locally on the Rundeck server
24+
- **Runner nodes**: If using Rundeck Enterprise with remote execution
25+
- **Both**: If you have a mixed environment
2226

23-
For now, you can install the kubernetes python SDK from this repo to have the OIDC support:
27+
You can install all dependencies using:
2428

29+
```bash
30+
pip install -r requirements.txt
2531
```
26-
git clone --recursive https://github.com/ltamaster/python
27-
cd python
28-
python setup.py install
2932

33+
Or install the kubernetes client directly:
34+
35+
```bash
36+
pip install 'kubernetes>=35.0.0'
37+
# or if pip3 is your command:
38+
pip3 install 'kubernetes>=35.0.0'
39+
```
40+
41+
**Version 35.0.0+ is required** to address security vulnerabilities in transitive dependencies. This version removes the dependency on `google-auth`, which had a vulnerable `pyasn1` dependency (CVE-2026-23490).
42+
43+
You can verify your installation with:
44+
45+
```bash
46+
python -m pip list | grep kubernetes
3047
```
3148

49+
Further information: [https://github.com/kubernetes-client/python](https://github.com/kubernetes-client/python)
50+
51+
### Python Version Support
52+
53+
- **Python 3.9+** is required (urllib3 2.6.x requires Python 3.9+)
54+
- **Python 3.10+** is recommended for best performance and security
55+
56+
### Kubernetes Cluster Compatibility
57+
58+
This plugin requires the Kubernetes Python client library version **35.0.0 or newer**.
59+
60+
The Kubernetes Python client is generally **backwards compatible** with older Kubernetes clusters. For the most accurate and up-to-date information about which Kubernetes API/server versions are supported by a given client version, refer to the upstream compatibility documentation:
61+
62+
- [Kubernetes Python Client Compatibility](https://github.com/kubernetes-client/python#compatibility)
63+
64+
In practice, upgrading the client library typically does not require upgrading your Kubernetes cluster, but you should verify compatibility against the upstream documentation and test in a non-production environment before making changes.
65+
66+
### Upgrading from Previous Plugin Versions
67+
68+
If you're upgrading from a previous version of this plugin (v2.0.16 or earlier), you **must** upgrade your Python dependencies to avoid security vulnerabilities.
69+
70+
**Run this command on each server where Rundeck executes jobs:**
71+
72+
```bash
73+
pip install --upgrade 'kubernetes>=35.0.0'
74+
# or if pip3 is your command:
75+
pip3 install --upgrade 'kubernetes>=35.0.0'
76+
```
77+
78+
**Where to run this command:**
79+
- **Rundeck server**: If jobs run locally on your Rundeck server
80+
- **Each Runner node**: If using Rundeck Enterprise with remote execution
81+
- **Both**: If you have a mixed environment
82+
83+
**Why the upgrade is required:**
84+
- Previous versions allowed any kubernetes client version, including older versions with security vulnerabilities
85+
- Version 35.0.0+ eliminates CVE-2026-23490 (High severity DoS vulnerability) by removing the vulnerable dependency chain
86+
- The upgrade is backwards compatible with your existing Kubernetes clusters
87+
88+
**What won't break:**
89+
- Your existing Kubernetes cluster version (no cluster upgrade required)
90+
- Your existing plugin configurations
91+
- Your existing Rundeck jobs and workflows
92+
- Communication with older Kubernetes API versions (v1.25, v1.28, v1.30, etc.)
93+
94+
**What happens if you don't upgrade:**
95+
- Jobs will continue to work (no immediate breakage)
96+
- A security warning will appear in job logs on every execution
97+
- Your installation remains vulnerable to CVE-2026-23490
98+
99+
**What changes:**
100+
- The Python kubernetes client library must be upgraded on all execution nodes
101+
- Any custom scripts or automation that install dependencies will need to use the new version
102+
32103
## Build and Install
33104

34105
Run `gradle build` to build the zip file. Then, copy the zip file to the `$RDECK_BASE\libext` folder.
35106

107+
## Testing
108+
109+
To run the tests specified in the `tox.ini` file, follow these steps:
110+
111+
- Install Tox: Ensure you have Tox installed. You can install it using pip:
112+
```sh
113+
pip install tox
114+
```
115+
- Run Tox: Execute Tox in the directory containing the `tox.ini` file. This will run the tests in all specified environments (Python 3.9, 3.10, 3.11, 3.12):
116+
```sh
117+
tox
118+
```
119+
- Run Specific Environment: If you want to run tests for a specific Python version, you can specify the environment:
120+
```sh
121+
tox -e py39 # For Python 3.9
122+
tox -e py310 # For Python 3.10
123+
tox -e py311 # For Python 3.11
124+
tox -e py312 # For Python 3.12
125+
```
36126

37127
## Authentication
38128

@@ -51,7 +141,7 @@ Otherwise, you can set the following parameters:
51141
This plugin allows getting the container pods from kubernetes as rundeck nodes.
52142

53143
* **Default attributes**: List of key=value pairs, example: username=root
54-
* **Custom Mapping**: Custom mapping adding on the rundeck nodes, for example: ```nodename.selector=default:Name,hostname.selector=default:pod_id```
144+
* **Custom Mapping**: Custom mapping adding on the rundeck nodes, for example: ```nodename.selector=default:name,hostname.selector=default:pod_id```
55145

56146
* **Tags**: List of tags. You can add static and custom tags, for example:
57147
```tag.selector=default:image, tag.selector=default:status, kubernetes```

contents/common.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,43 @@
2727
if os.environ.get('RD_JOB_LOGLEVEL') == 'DEBUG':
2828
log.setLevel(logging.DEBUG)
2929

30+
# Check kubernetes client version and warn if outdated
31+
try:
32+
from packaging import version
33+
from packaging.version import InvalidVersion
34+
except ImportError:
35+
version = None
36+
InvalidVersion = None
37+
38+
if version is not None:
39+
MIN_KUBERNETES_VERSION = "35.0.0"
40+
try:
41+
import kubernetes
42+
current_version = kubernetes.__version__
43+
try:
44+
if version.parse(current_version) < version.parse(MIN_KUBERNETES_VERSION):
45+
log.warning("=" * 80)
46+
log.warning("SECURITY WARNING: Outdated Kubernetes Python client detected")
47+
log.warning(f"Current version: {current_version}")
48+
log.warning(f"Required version: {MIN_KUBERNETES_VERSION}+")
49+
log.warning("")
50+
log.warning("Your installation is vulnerable to CVE-2026-23490 (CVSS 7.5 HIGH)")
51+
log.warning("")
52+
log.warning("ACTION REQUIRED: Upgrade the kubernetes Python library on the")
53+
log.warning("server where Rundeck is running (or on your Runner if using")
54+
log.warning("remote execution):")
55+
log.warning("")
56+
log.warning(f" pip install --upgrade 'kubernetes>={MIN_KUBERNETES_VERSION}'")
57+
log.warning(f" # or: pip3 install --upgrade 'kubernetes>={MIN_KUBERNETES_VERSION}'")
58+
log.warning("")
59+
log.warning("The plugin will continue to work, but you should upgrade to")
60+
log.warning("eliminate the security vulnerability.")
61+
log.warning("=" * 80)
62+
except InvalidVersion:
63+
pass
64+
except (AttributeError, ImportError):
65+
pass
66+
3067

3168
def connect():
3269
config_file = None
@@ -323,11 +360,12 @@ def parseJson(obj):
323360

324361

325362
def create_pod_template_spec(data):
326-
ports = []
327363

328-
for port in data["ports"].split(','):
329-
portDefinition = client.V1ContainerPort(container_port=int(port))
330-
ports.append(portDefinition)
364+
ports = []
365+
if data["ports"]:
366+
for port in data["ports"].split(','):
367+
portDefinition = client.V1ContainerPort(container_port=int(port))
368+
ports.append(portDefinition)
331369

332370
envs = []
333371
if "environments" in data:

contents/deployment-update.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,15 @@ def create_deployment_object(data):
106106
template.metadata = client.V1ObjectMeta(labels=labels)
107107

108108
# Create the specification of deployment
109-
spec = client.ExtensionsV1beta1DeploymentSpec(
109+
spec = client.V1DeploymentSpec(
110110
replicas=int(data["replicas"]),
111-
template=template)
111+
template=template,
112+
selector=client.V1LabelSelector(
113+
match_labels={} # This will match all pods
114+
)
115+
)
112116
# Instantiate the deployment object
113-
deployment = client.ExtensionsV1beta1Deployment(
117+
deployment = client.V1Deployment(
114118
api_version=data["api_version"],
115119
kind="Deployment",
116120
metadata=client.V1ObjectMeta(labels=labels,

contents/pod-describe.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python -u
2+
import logging
3+
import sys
4+
import os
5+
import common
6+
7+
from kubernetes import client
8+
from kubernetes.client.rest import ApiException
9+
10+
11+
logging.basicConfig(stream=sys.stderr, level=logging.INFO,
12+
format='%(levelname)s: %(name)s: %(message)s')
13+
log = logging.getLogger('kubernetes-model-source')
14+
15+
16+
def main():
17+
18+
pod_name = os.environ.get('RD_CONFIG_NAME')
19+
namespace = os.environ.get('RD_CONFIG_NAMESPACE')
20+
21+
if not pod_name:
22+
[pod_name, namespace, container] = common.get_core_node_parameter_list()
23+
24+
common.connect()
25+
26+
try:
27+
api = client.CoreV1Api()
28+
29+
api_response = api.read_namespaced_pod(
30+
name=pod_name,
31+
namespace=namespace)
32+
33+
print(common.parseJson(api_response.status))
34+
35+
except ApiException:
36+
log.exception("Exception deleting deployment:")
37+
sys.exit(1)
38+
39+
40+
if __name__ == '__main__':
41+
main()

contents/pods-resource-model.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ def nodeCollectData(pod, container, defaults, taglist, mappingList, boEmoticon):
137137
data['terminated'] = terminated
138138

139139
# Add labels as its own map of node attributes.
140-
for key, value in pod.metadata.labels.items():
141-
data['labels:' + key] = value
140+
if pod.metadata.labels is not None:
141+
for key, value in pod.metadata.labels.items():
142+
data['labels:' + key] = value
142143

143144
emoticon = ""
144145
if default_settings['default:status'] == "running":

0 commit comments

Comments
 (0)