mirror of
https://github.com/openshift/community.okd.git
synced 2026-03-26 19:03:14 +00:00
* Upgrade Ansible and OKD versions for CI * Use ubi9 and fix sanity * Use correct pip install * Try using quotes * Ensure python3.9 * Upgrade ansible and molecule versions * Remove DeploymentConfig DeploymentConfigs are deprecated and seem to now be causing idempotence problems. Replacing them with Deployments fixes it. * Attempt to fix ldap integration tests Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Move sanity and unit tests to GH actions Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Firt round of sanity fixes Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add kubernetes.core collection as sanity requirement Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add ignore-2.16.txt Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Attempt to fix units Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add ignore-2.17 Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Attempt to fix unit tests Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add pytest-ansible to test-requirements.txt Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add changelog fragment Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add workflow for ansible-lint Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Apply black Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Fix linters Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Add # fmt: skip Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Yet another round of linting Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Yet another round of linting Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Remove setup.cfg Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Revert #fmt Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Use ansible-core 2.14 Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Cleanup ansible-lint ignores Signed-off-by: Alina Buzachis <abuzachis@redhat.com> * Try using service instead of pod IP * Fix typo * Actually use the correct port * See if NetworkPolicy is preventing connection * using Pod internal IP * fix adm prune auth roles syntax * adding some retry steps * fix: openshift_builds target * add flag --force-with-deps when building downstream collection * Remove yamllint from tox linters, bump minimum python supported version to 3.9, Remove support for ansible-core < 2.14 --------- Signed-off-by: Alina Buzachis <abuzachis@redhat.com> Co-authored-by: Mike Graves <mgraves@redhat.com> Co-authored-by: Alina Buzachis <abuzachis@redhat.com>
This commit is contained in:
5
.config/ansible-lint.yml
Normal file
5
.config/ansible-lint.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
profile: production
|
||||
exclude_paths:
|
||||
- molecule
|
||||
- tests/sanity
|
||||
4
.github/patchback.yml
vendored
Normal file
4
.github/patchback.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
backport_branch_prefix: patchback/backports/
|
||||
backport_label_prefix: backport-
|
||||
target_branch_prefix: stable-
|
||||
6
.github/settings.yml
vendored
Normal file
6
.github/settings.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# DO NOT MODIFY
|
||||
|
||||
# Settings: https://probot.github.io/apps/settings/
|
||||
# Pull settings from https://github.com/ansible-collections/.github/blob/master/.github/settings.yml
|
||||
_extends: ".github"
|
||||
60
.github/stale.yml
vendored
Normal file
60
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 90
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale
|
||||
# label is closed. Set to false to disable. If disabled, issues still need to be
|
||||
# closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 30
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale.
|
||||
# Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set
|
||||
# to `[]` to disable
|
||||
exemptLabels:
|
||||
- security
|
||||
- planned
|
||||
- priority/critical
|
||||
- lifecycle/frozen
|
||||
- verified
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: lifecycle/stale
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
pulls:
|
||||
markComment: |-
|
||||
PRs go stale after 90 days of inactivity.
|
||||
If there is no further activity, the PR will be closed in another 30 days.
|
||||
|
||||
unmarkComment: >-
|
||||
This pull request is no longer stale.
|
||||
|
||||
closeComment: >-
|
||||
This pull request has been closed due to inactivity.
|
||||
|
||||
issues:
|
||||
markComment: |-
|
||||
Issues go stale after 90 days of inactivity.
|
||||
If there is no further activity, the issue will be closed in another 30 days.
|
||||
|
||||
unmarkComment: >-
|
||||
This issue is no longer stale.
|
||||
|
||||
closeComment: >-
|
||||
This issue has been closed due to inactivity.
|
||||
23
.github/workflows/changelog.yml
vendored
Normal file
23
.github/workflows/changelog.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Changelog
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- labeled
|
||||
- unlabeled
|
||||
- synchronize
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
uses: ansible-network/github_actions/.github/workflows/changelog.yml@main
|
||||
29
.github/workflows/linters.yml
vendored
Normal file
29
.github/workflows/linters.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Linters
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- labeled
|
||||
- unlabeled
|
||||
- synchronize
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
tags:
|
||||
- '*'
|
||||
jobs:
|
||||
linters:
|
||||
uses: ansible-network/github_actions/.github/workflows/tox-linters.yml@main
|
||||
ansible-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: ansible-network/github_actions/.github/actions/checkout_dependency@main
|
||||
|
||||
- name: Run ansible-lint
|
||||
uses: ansible/ansible-lint@v6.21.0
|
||||
23
.github/workflows/sanity-tests.yml
vendored
Normal file
23
.github/workflows/sanity-tests.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Sanity tests
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
sanity:
|
||||
uses: ansible-network/github_actions/.github/workflows/sanity.yml@main
|
||||
with:
|
||||
collection_pre_install: '-r source/tests/sanity/requirements.yml'
|
||||
21
.github/workflows/unit-tests.yml
vendored
Normal file
21
.github/workflows/unit-tests.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: Unit tests
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
unit-source:
|
||||
uses: ansible-network/github_actions/.github/workflows/unit_source.yml@main
|
||||
44
.yamllint
44
.yamllint
@@ -1,33 +1,15 @@
|
||||
---
|
||||
# Based on ansible-lint config
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
braces:
|
||||
max-spaces-inside: 1
|
||||
level: error
|
||||
brackets:
|
||||
max-spaces-inside: 1
|
||||
level: error
|
||||
colons:
|
||||
max-spaces-after: -1
|
||||
level: error
|
||||
commas:
|
||||
max-spaces-after: -1
|
||||
level: error
|
||||
comments: disable
|
||||
comments-indentation: disable
|
||||
document-start: disable
|
||||
empty-lines:
|
||||
max: 3
|
||||
level: error
|
||||
hyphens:
|
||||
level: error
|
||||
indentation: disable
|
||||
key-duplicates: enable
|
||||
line-length: disable
|
||||
new-line-at-end-of-file: disable
|
||||
new-lines:
|
||||
type: unix
|
||||
trailing-spaces: disable
|
||||
truthy: disable
|
||||
indentation:
|
||||
ignore: &default_ignores |
|
||||
# automatically generated, we can't control it
|
||||
changelogs/changelog.yaml
|
||||
# Will be gone when we release and automatically reformatted
|
||||
changelogs/fragments/*
|
||||
document-start:
|
||||
ignore: *default_ignores
|
||||
line-length:
|
||||
ignore: *default_ignores
|
||||
max: 160
|
||||
|
||||
ignore-from-file: .gitignore
|
||||
|
||||
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ build: clean
|
||||
ansible-galaxy collection build
|
||||
|
||||
install: build
|
||||
ansible-galaxy collection install -p ansible_collections community-okd-$(VERSION).tar.gz
|
||||
ansible-galaxy collection install --force -p ansible_collections community-okd-$(VERSION).tar.gz
|
||||
|
||||
sanity: install
|
||||
cd ansible_collections/community/okd && ansible-test sanity -v --python $(PYTHON_VERSION) $(SANITY_TEST_ARGS)
|
||||
|
||||
@@ -10,13 +10,8 @@ The collection includes a variety of Ansible content to help automate the manage
|
||||
<!--start requires_ansible-->
|
||||
## Ansible version compatibility
|
||||
|
||||
This collection has been tested against following Ansible versions: **>=2.9.17**.
|
||||
This collection has been tested against following Ansible versions: **>=2.14.0**.
|
||||
|
||||
For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
|
||||
fully qualified collection name (for example, `cisco.ios.ios`).
|
||||
Plugins and modules within a collection may be tested with only specific Ansible versions.
|
||||
A collection may contain metadata that identifies these versions.
|
||||
PEP440 is the schema used to describe the versions of Ansible.
|
||||
<!--end requires_ansible-->
|
||||
|
||||
## Python Support
|
||||
|
||||
@@ -1,201 +1,202 @@
|
||||
---
|
||||
ancestor: null
|
||||
releases:
|
||||
0.1.0:
|
||||
changes:
|
||||
major_changes:
|
||||
- Add custom k8s module, integrate better Molecule tests (https://github.com/ansible-collections/community.okd/pull/7).
|
||||
- Add downstream build scripts to build redhat.openshift (https://github.com/ansible-collections/community.okd/pull/20).
|
||||
- Add openshift connection plugin, update inventory plugin to use it (https://github.com/ansible-collections/community.okd/pull/18).
|
||||
- Initial content migration from community.kubernetes (https://github.com/ansible-collections/community.okd/pull/3).
|
||||
- Add custom k8s module, integrate better Molecule tests (https://github.com/ansible-collections/community.okd/pull/7).
|
||||
- Add downstream build scripts to build redhat.openshift (https://github.com/ansible-collections/community.okd/pull/20).
|
||||
- Add openshift connection plugin, update inventory plugin to use it (https://github.com/ansible-collections/community.okd/pull/18).
|
||||
- Initial content migration from community.kubernetes (https://github.com/ansible-collections/community.okd/pull/3).
|
||||
minor_changes:
|
||||
- Add incluster Makefile target for CI (https://github.com/ansible-collections/community.okd/pull/13).
|
||||
- Add tests for inventory plugin (https://github.com/ansible-collections/community.okd/pull/16).
|
||||
- CI Documentation for working with Prow (https://github.com/ansible-collections/community.okd/pull/15).
|
||||
- Docker container can run as an arbitrary user (https://github.com/ansible-collections/community.okd/pull/12).
|
||||
- Dockerfile now is properly set up to run tests in a rootless container (https://github.com/ansible-collections/community.okd/pull/11).
|
||||
- Integrate stale bot for issue queue maintenance (https://github.com/ansible-collections/community.okd/pull/14).
|
||||
- Add incluster Makefile target for CI (https://github.com/ansible-collections/community.okd/pull/13).
|
||||
- Add tests for inventory plugin (https://github.com/ansible-collections/community.okd/pull/16).
|
||||
- CI Documentation for working with Prow (https://github.com/ansible-collections/community.okd/pull/15).
|
||||
- Docker container can run as an arbitrary user (https://github.com/ansible-collections/community.okd/pull/12).
|
||||
- Dockerfile now is properly set up to run tests in a rootless container (https://github.com/ansible-collections/community.okd/pull/11).
|
||||
- Integrate stale bot for issue queue maintenance (https://github.com/ansible-collections/community.okd/pull/14).
|
||||
fragments:
|
||||
- 1-initial-content.yml
|
||||
- 11-dockerfile-tests.yml
|
||||
- 12-dockerfile-tests.yml
|
||||
- 13-makefile-tests.yml
|
||||
- 15-ci-documentation.yml
|
||||
- 16-inventory-plugin-tests.yml
|
||||
- 18-openshift-connection-plugin.yml
|
||||
- 20-downstream-build-scripts.yml
|
||||
- 7-molecule-tests.yml
|
||||
- 8-stale-bot.yml
|
||||
- 1-initial-content.yml
|
||||
- 11-dockerfile-tests.yml
|
||||
- 12-dockerfile-tests.yml
|
||||
- 13-makefile-tests.yml
|
||||
- 15-ci-documentation.yml
|
||||
- 16-inventory-plugin-tests.yml
|
||||
- 18-openshift-connection-plugin.yml
|
||||
- 20-downstream-build-scripts.yml
|
||||
- 7-molecule-tests.yml
|
||||
- 8-stale-bot.yml
|
||||
release_date: '2020-09-04'
|
||||
0.2.0:
|
||||
changes:
|
||||
major_changes:
|
||||
- openshift_auth - new module (migrated from k8s_auth in community.kubernetes)
|
||||
(https://github.com/ansible-collections/community.okd/pull/33).
|
||||
- openshift_auth - new module (migrated from k8s_auth in community.kubernetes)
|
||||
(https://github.com/ansible-collections/community.okd/pull/33).
|
||||
minor_changes:
|
||||
- Add a contribution guide (https://github.com/ansible-collections/community.okd/pull/37).
|
||||
- Use the API Group APIVersion for the `Route` object (https://github.com/ansible-collections/community.okd/pull/27).
|
||||
- Add a contribution guide (https://github.com/ansible-collections/community.okd/pull/37).
|
||||
- Use the API Group APIVersion for the `Route` object (https://github.com/ansible-collections/community.okd/pull/27).
|
||||
fragments:
|
||||
- 27-route-api-group.yml
|
||||
- 33-add-k8s_auth.yml
|
||||
- 36-contribution-guide.yml
|
||||
- 27-route-api-group.yml
|
||||
- 33-add-k8s_auth.yml
|
||||
- 36-contribution-guide.yml
|
||||
modules:
|
||||
- description: Authenticate to OpenShift clusters which require an explicit login
|
||||
step
|
||||
name: openshift_auth
|
||||
namespace: ''
|
||||
- description: Authenticate to OpenShift clusters which require an explicit login
|
||||
step
|
||||
name: openshift_auth
|
||||
namespace: ''
|
||||
release_date: '2020-09-24'
|
||||
0.3.0:
|
||||
changes:
|
||||
major_changes:
|
||||
- Add openshift_process module for template rendering and optional application
|
||||
of rendered resources (https://github.com/ansible-collections/community.okd/pull/44).
|
||||
- Add openshift_route module for creating routes from services (https://github.com/ansible-collections/community.okd/pull/40).
|
||||
- Add openshift_process module for template rendering and optional application
|
||||
of rendered resources (https://github.com/ansible-collections/community.okd/pull/44).
|
||||
- Add openshift_route module for creating routes from services (https://github.com/ansible-collections/community.okd/pull/40).
|
||||
fragments:
|
||||
- 40-openshift_route.yml
|
||||
- 44-openshift_process.yml
|
||||
- 40-openshift_route.yml
|
||||
- 44-openshift_process.yml
|
||||
modules:
|
||||
- description: Process an OpenShift template.openshift.io/v1 Template
|
||||
name: openshift_process
|
||||
namespace: ''
|
||||
- description: Expose a Service as an OpenShift Route.
|
||||
name: openshift_route
|
||||
namespace: ''
|
||||
- description: Process an OpenShift template.openshift.io/v1 Template
|
||||
name: openshift_process
|
||||
namespace: ''
|
||||
- description: Expose a Service as an OpenShift Route.
|
||||
name: openshift_route
|
||||
namespace: ''
|
||||
release_date: '2020-10-12'
|
||||
1.0.0:
|
||||
changes:
|
||||
minor_changes:
|
||||
- Released version 1 to Automation Hub as redhat.openshift (https://github.com/ansible-collections/community.okd/issues/51).
|
||||
- Released version 1 to Automation Hub as redhat.openshift (https://github.com/ansible-collections/community.okd/issues/51).
|
||||
fragments:
|
||||
- 51-redhat-openshift-ah-release.yml
|
||||
- 51-redhat-openshift-ah-release.yml
|
||||
release_date: '2020-11-12'
|
||||
1.0.1:
|
||||
changes:
|
||||
bugfixes:
|
||||
- Generate downstream redhat.openshift documentation (https://github.com/ansible-collections/community.okd/pull/59).
|
||||
- Generate downstream redhat.openshift documentation (https://github.com/ansible-collections/community.okd/pull/59).
|
||||
fragments:
|
||||
- 59-downstream-docs.yml
|
||||
- 59-downstream-docs.yml
|
||||
release_date: '2020-11-17'
|
||||
1.0.2:
|
||||
changes:
|
||||
minor_changes:
|
||||
- restrict the version of kubernetes.core dependency (https://github.com/ansible-collections/community.okd/pull/66).
|
||||
- restrict the version of kubernetes.core dependency (https://github.com/ansible-collections/community.okd/pull/66).
|
||||
fragments:
|
||||
- 66-restrict-kubernetes-core-version.yaml
|
||||
- 66-restrict-kubernetes-core-version.yaml
|
||||
release_date: '2021-02-19'
|
||||
1.1.0:
|
||||
changes:
|
||||
minor_changes:
|
||||
- increase the kubernetes.core dependency version number (https://github.com/ansible-collections/community.okd/pull/71).
|
||||
- increase the kubernetes.core dependency version number (https://github.com/ansible-collections/community.okd/pull/71).
|
||||
fragments:
|
||||
- 71-bump-kubernetes-core-version.yaml
|
||||
- 71-bump-kubernetes-core-version.yaml
|
||||
release_date: '2021-02-23'
|
||||
1.1.1:
|
||||
changes:
|
||||
bugfixes:
|
||||
- add missing requirements.txt file needed for execution environments (https://github.com/ansible-collections/community.okd/pull/78).
|
||||
- openshift_route - default to ``no_log=False`` for the ``key`` parameter in
|
||||
TLS configuration to fix sanity failures (https://github.com/ansible-collections/community.okd/pull/77).
|
||||
- restrict molecule version to <3.3.0 to address breaking change (https://github.com/ansible-collections/community.okd/pull/77).
|
||||
- update CI to work with ansible 2.11 (https://github.com/ansible-collections/community.okd/pull/80).
|
||||
- add missing requirements.txt file needed for execution environments (https://github.com/ansible-collections/community.okd/pull/78).
|
||||
- openshift_route - default to ``no_log=False`` for the ``key`` parameter in
|
||||
TLS configuration to fix sanity failures (https://github.com/ansible-collections/community.okd/pull/77).
|
||||
- restrict molecule version to <3.3.0 to address breaking change (https://github.com/ansible-collections/community.okd/pull/77).
|
||||
- update CI to work with ansible 2.11 (https://github.com/ansible-collections/community.okd/pull/80).
|
||||
fragments:
|
||||
- 77-fix-ci-failure.yaml
|
||||
- 78-add-requirements-file.yaml
|
||||
- 80-update-ci.yaml
|
||||
- 77-fix-ci-failure.yaml
|
||||
- 78-add-requirements-file.yaml
|
||||
- 80-update-ci.yaml
|
||||
release_date: '2021-04-06'
|
||||
1.1.2:
|
||||
changes:
|
||||
bugfixes:
|
||||
- include requirements.txt in downstream build process (https://github.com/ansible-collections/community.okd/pull/81).
|
||||
- include requirements.txt in downstream build process (https://github.com/ansible-collections/community.okd/pull/81).
|
||||
fragments:
|
||||
- 81-include-requirements.yaml
|
||||
- 81-include-requirements.yaml
|
||||
release_date: '2021-04-08'
|
||||
2.0.0:
|
||||
changes:
|
||||
breaking_changes:
|
||||
- drop python 2 support (https://github.com/openshift/community.okd/pull/93).
|
||||
- drop python 2 support (https://github.com/openshift/community.okd/pull/93).
|
||||
bugfixes:
|
||||
- fixes test suite to use correct versions of python and dependencies (https://github.com/ansible-collections/community.okd/pull/89).
|
||||
- openshift_process - fix module execution when template does not include a
|
||||
message (https://github.com/ansible-collections/community.okd/pull/87).
|
||||
- fixes test suite to use correct versions of python and dependencies (https://github.com/ansible-collections/community.okd/pull/89).
|
||||
- openshift_process - fix module execution when template does not include a
|
||||
message (https://github.com/ansible-collections/community.okd/pull/87).
|
||||
major_changes:
|
||||
- update to use kubernetes.core 2.0 (https://github.com/openshift/community.okd/pull/93).
|
||||
- update to use kubernetes.core 2.0 (https://github.com/openshift/community.okd/pull/93).
|
||||
minor_changes:
|
||||
- Added documentation for the ``community.okd`` collection.
|
||||
- openshift - inventory plugin supports FQCN ``redhat.openshift``.
|
||||
- Added documentation for the ``community.okd`` collection.
|
||||
- openshift - inventory plugin supports FQCN ``redhat.openshift``.
|
||||
fragments:
|
||||
- 87-openshift_process-fix-template-without-message.yaml
|
||||
- 89-clean-up-ci.yaml
|
||||
- 93-update-to-k8s-2.yaml
|
||||
- add_docs.yml
|
||||
- fqcn_inventory.yml
|
||||
- 87-openshift_process-fix-template-without-message.yaml
|
||||
- 89-clean-up-ci.yaml
|
||||
- 93-update-to-k8s-2.yaml
|
||||
- add_docs.yml
|
||||
- fqcn_inventory.yml
|
||||
release_date: '2021-06-22'
|
||||
2.0.1:
|
||||
changes:
|
||||
minor_changes:
|
||||
- increase kubernetes.core dependency version (https://github.com/openshift/community.okd/pull/97).
|
||||
- increase kubernetes.core dependency version (https://github.com/openshift/community.okd/pull/97).
|
||||
fragments:
|
||||
- 97-bump-k8s-version.yaml
|
||||
- 97-bump-k8s-version.yaml
|
||||
release_date: '2021-06-24'
|
||||
2.1.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- fix broken links in Automation Hub for redhat.openshift (https://github.com/openshift/community.okd/issues/100).
|
||||
- fix broken links in Automation Hub for redhat.openshift (https://github.com/openshift/community.okd/issues/100).
|
||||
minor_changes:
|
||||
- add support for turbo mode (https://github.com/openshift/community.okd/pull/102).
|
||||
- openshift_route - Add support for Route annotations (https://github.com/ansible-collections/community.okd/pull/99).
|
||||
- add support for turbo mode (https://github.com/openshift/community.okd/pull/102).
|
||||
- openshift_route - Add support for Route annotations (https://github.com/ansible-collections/community.okd/pull/99).
|
||||
fragments:
|
||||
- 0-copy_ignore_txt.yml
|
||||
- 100-fix-broken-links.yml
|
||||
- 102-support-turbo-mode.yaml
|
||||
- 99-openshift_route-add-support-for-annotations.yml
|
||||
- 0-copy_ignore_txt.yml
|
||||
- 100-fix-broken-links.yml
|
||||
- 102-support-turbo-mode.yaml
|
||||
- 99-openshift_route-add-support-for-annotations.yml
|
||||
release_date: '2021-10-20'
|
||||
2.2.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- fix ocp auth failing against cluster api url with trailing slash (https://github.com/openshift/community.okd/issues/139)
|
||||
- fix ocp auth failing against cluster api url with trailing slash (https://github.com/openshift/community.okd/issues/139)
|
||||
minor_changes:
|
||||
- add action groups to runtime.yml (https://github.com/openshift/community.okd/issues/41).
|
||||
- add action groups to runtime.yml (https://github.com/openshift/community.okd/issues/41).
|
||||
fragments:
|
||||
- 152-add-action-groups.yml
|
||||
- auth-against-api-with-trailing-slash.yaml
|
||||
- 152-add-action-groups.yml
|
||||
- auth-against-api-with-trailing-slash.yaml
|
||||
modules:
|
||||
- description: Update TemplateInstances to point to the latest group-version-kinds
|
||||
name: openshift_adm_migrate_template_instances
|
||||
namespace: ''
|
||||
- description: Removes references to the specified roles, clusterroles, users,
|
||||
and groups
|
||||
name: openshift_adm_prune_auth
|
||||
namespace: ''
|
||||
- description: Remove old completed and failed deployment configs
|
||||
name: openshift_adm_prune_deployments
|
||||
namespace: ''
|
||||
- description: Remove unreferenced images
|
||||
name: openshift_adm_prune_images
|
||||
namespace: ''
|
||||
- description: Import the latest image information from a tag in a container image
|
||||
registry.
|
||||
name: openshift_import_image
|
||||
namespace: ''
|
||||
- description: Display information about the integrated registry.
|
||||
name: openshift_registry_info
|
||||
namespace: ''
|
||||
- description: Update TemplateInstances to point to the latest group-version-kinds
|
||||
name: openshift_adm_migrate_template_instances
|
||||
namespace: ''
|
||||
- description: Removes references to the specified roles, clusterroles, users,
|
||||
and groups
|
||||
name: openshift_adm_prune_auth
|
||||
namespace: ''
|
||||
- description: Remove old completed and failed deployment configs
|
||||
name: openshift_adm_prune_deployments
|
||||
namespace: ''
|
||||
- description: Remove unreferenced images
|
||||
name: openshift_adm_prune_images
|
||||
namespace: ''
|
||||
- description: Import the latest image information from a tag in a container image
|
||||
registry.
|
||||
name: openshift_import_image
|
||||
namespace: ''
|
||||
- description: Display information about the integrated registry.
|
||||
name: openshift_registry_info
|
||||
namespace: ''
|
||||
release_date: '2022-05-05'
|
||||
2.3.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- openshift_adm_groups_sync - initialize OpenshiftGroupSync attributes early
|
||||
to avoid Attribute error (https://github.com/openshift/community.okd/issues/155).
|
||||
- openshift_auth - Review the way the discard process is working, add openshift
|
||||
algorithm to convert token to resource object name (https://github.com/openshift/community.okd/issues/176).
|
||||
- openshift_adm_groups_sync - initialize OpenshiftGroupSync attributes early
|
||||
to avoid Attribute error (https://github.com/openshift/community.okd/issues/155).
|
||||
- openshift_auth - Review the way the discard process is working, add openshift
|
||||
algorithm to convert token to resource object name (https://github.com/openshift/community.okd/issues/176).
|
||||
fragments:
|
||||
- 165-initialize-attributes-early.yml
|
||||
- 178-openshift_auth-fix-revoke-token.yml
|
||||
- 180-default-values-doc.yml
|
||||
- 165-initialize-attributes-early.yml
|
||||
- 178-openshift_auth-fix-revoke-token.yml
|
||||
- 180-default-values-doc.yml
|
||||
modules:
|
||||
- description: Prune old completed and failed builds
|
||||
name: openshift_adm_prune_builds
|
||||
namespace: ''
|
||||
- description: Start a new build or Cancel running, pending, or new builds.
|
||||
name: openshift_build
|
||||
namespace: ''
|
||||
- description: Prune old completed and failed builds
|
||||
name: openshift_adm_prune_builds
|
||||
namespace: ''
|
||||
- description: Start a new build or Cancel running, pending, or new builds.
|
||||
name: openshift_build
|
||||
namespace: ''
|
||||
release_date: '2023-02-03'
|
||||
|
||||
@@ -10,21 +10,21 @@ notesdir: fragments
|
||||
prelude_section_name: release_summary
|
||||
prelude_section_title: Release Summary
|
||||
sections:
|
||||
- - major_changes
|
||||
- Major Changes
|
||||
- - minor_changes
|
||||
- Minor Changes
|
||||
- - breaking_changes
|
||||
- Breaking Changes / Porting Guide
|
||||
- - deprecated_features
|
||||
- Deprecated Features
|
||||
- - removed_features
|
||||
- Removed Features (previously deprecated)
|
||||
- - security_fixes
|
||||
- Security Fixes
|
||||
- - bugfixes
|
||||
- Bugfixes
|
||||
- - known_issues
|
||||
- Known Issues
|
||||
- - major_changes
|
||||
- Major Changes
|
||||
- - minor_changes
|
||||
- Minor Changes
|
||||
- - breaking_changes
|
||||
- Breaking Changes / Porting Guide
|
||||
- - deprecated_features
|
||||
- Deprecated Features
|
||||
- - removed_features
|
||||
- Removed Features (previously deprecated)
|
||||
- - security_fixes
|
||||
- Security Fixes
|
||||
- - bugfixes
|
||||
- Bugfixes
|
||||
- - known_issues
|
||||
- Known Issues
|
||||
title: OKD Collection
|
||||
trivial_section_name: trivial
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
---
|
||||
deprecated_features:
|
||||
- openshift - the ``openshift`` inventory plugin has been deprecated and will be removed in release 4.0.0 (https://github.com/ansible-collections/kubernetes.core/issues/31).
|
||||
- openshift - the ``openshift`` inventory plugin has been deprecated and will be removed in release 4.0.0
|
||||
(https://github.com/ansible-collections/kubernetes.core/issues/31).
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
trivial:
|
||||
- "Move unit and sanity tests from zuul to GitHub Actions (https://github.com/openshift/community.okd/pull/202)."
|
||||
breaking_changes:
|
||||
- "Remove support for ansible-core < 2.14 (https://github.com/openshift/community.okd/pull/202)."
|
||||
- "Bump minimum Python suupported version to 3.9 (https://github.com/openshift/community.okd/pull/202)."
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry.access.redhat.com/ubi8/ubi
|
||||
FROM registry.access.redhat.com/ubi9/ubi
|
||||
|
||||
ENV OPERATOR=/usr/local/bin/ansible-operator \
|
||||
USER_UID=1001 \
|
||||
@@ -11,20 +11,20 @@ RUN yum install -y \
|
||||
glibc-langpack-en \
|
||||
git \
|
||||
make \
|
||||
python39 \
|
||||
python39-devel \
|
||||
python39-pip \
|
||||
python39-setuptools \
|
||||
python3 \
|
||||
python3-devel \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
gcc \
|
||||
openldap-devel \
|
||||
&& pip3 install --no-cache-dir --upgrade setuptools pip \
|
||||
&& pip3 install --no-cache-dir \
|
||||
&& python3.9 -m pip install --no-cache-dir --upgrade setuptools pip \
|
||||
&& python3.9 -m pip install --no-cache-dir \
|
||||
kubernetes \
|
||||
ansible==2.9.* \
|
||||
"molecule<3.3.0" \
|
||||
"ansible-core" \
|
||||
"molecule" \
|
||||
&& yum clean all \
|
||||
&& rm -rf $HOME/.cache \
|
||||
&& curl -L https://github.com/openshift/okd/releases/download/4.5.0-0.okd-2020-08-12-020541/openshift-client-linux-4.5.0-0.okd-2020-08-12-020541.tar.gz | tar -xz -C /usr/local/bin
|
||||
&& curl -L https://github.com/openshift/okd/releases/download/4.12.0-0.okd-2023-04-16-041331/openshift-client-linux-4.12.0-0.okd-2023-04-16-041331.tar.gz | tar -xz -C /usr/local/bin
|
||||
# TODO: Is there a better way to install this client in ubi8?
|
||||
|
||||
COPY . /opt/ansible
|
||||
|
||||
@@ -47,7 +47,7 @@ f_text_sub()
|
||||
sed -i.bak "s/Kubernetes/OpenShift/g" "${_build_dir}/galaxy.yml"
|
||||
sed -i.bak "s/^version\:.*$/version: ${DOWNSTREAM_VERSION}/" "${_build_dir}/galaxy.yml"
|
||||
sed -i.bak "/STARTREMOVE/,/ENDREMOVE/d" "${_build_dir}/README.md"
|
||||
sed -i.bak "s/[[:space:]]okd:$/ openshift:/" ${_build_dir}/meta/runtime.yml
|
||||
sed -i.bak "s/[[:space:]]okd:$/ openshift:/" "${_build_dir}/meta/runtime.yml"
|
||||
|
||||
find "${_build_dir}" -type f ! -name galaxy.yml -exec sed -i.bak "s/community\.okd/redhat\.openshift/g" {} \;
|
||||
find "${_build_dir}" -type f -name "*.bak" -delete
|
||||
@@ -67,7 +67,6 @@ f_prep()
|
||||
LICENSE
|
||||
README.md
|
||||
Makefile
|
||||
setup.cfg
|
||||
.yamllint
|
||||
requirements.txt
|
||||
requirements.yml
|
||||
@@ -76,6 +75,7 @@ f_prep()
|
||||
|
||||
# Directories to recursively copy downstream (relative repo root dir path)
|
||||
_dir_manifest=(
|
||||
.config
|
||||
changelogs
|
||||
ci
|
||||
meta
|
||||
@@ -156,7 +156,7 @@ f_handle_doc_fragments_workaround()
|
||||
# Build the collection, export docs, render them, stitch it all back together
|
||||
pushd "${_build_dir}" || return
|
||||
ansible-galaxy collection build
|
||||
ansible-galaxy collection install -p "${install_collections_dir}" ./*.tar.gz
|
||||
ansible-galaxy collection install --force-with-deps -p "${install_collections_dir}" ./*.tar.gz
|
||||
rm ./*.tar.gz
|
||||
for doc_fragment_mod in "${_doc_fragment_modules[@]}"
|
||||
do
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
requires_ansible: '>=2.9.17'
|
||||
requires_ansible: '>=2.14.0'
|
||||
action_groups:
|
||||
okd:
|
||||
- k8s
|
||||
|
||||
@@ -21,16 +21,13 @@
|
||||
debug:
|
||||
var: output
|
||||
|
||||
- name: Create deployment config
|
||||
- name: Create deployment
|
||||
community.okd.k8s:
|
||||
state: present
|
||||
name: hello-world
|
||||
namespace: testing
|
||||
definition: '{{ okd_dc_template }}'
|
||||
wait: yes
|
||||
wait_condition:
|
||||
type: Available
|
||||
status: True
|
||||
vars:
|
||||
k8s_pod_name: hello-world
|
||||
k8s_pod_image: python
|
||||
@@ -71,19 +68,12 @@
|
||||
namespace: '{{ namespace }}'
|
||||
definition: '{{ okd_imagestream_template }}'
|
||||
|
||||
- name: Create DeploymentConfig to reference ImageStream
|
||||
community.okd.k8s:
|
||||
name: '{{ k8s_pod_name }}'
|
||||
namespace: '{{ namespace }}'
|
||||
definition: '{{ okd_dc_template }}'
|
||||
vars:
|
||||
k8s_pod_name: is-idempotent-dc
|
||||
|
||||
- name: Create Deployment to reference ImageStream
|
||||
community.okd.k8s:
|
||||
name: '{{ k8s_pod_name }}'
|
||||
namespace: '{{ namespace }}'
|
||||
definition: '{{ k8s_deployment_template | combine(metadata) }}'
|
||||
wait: true
|
||||
vars:
|
||||
k8s_pod_annotations:
|
||||
"alpha.image.policy.openshift.io/resolve-names": "*"
|
||||
|
||||
@@ -10,14 +10,14 @@ objects:
|
||||
name: "Pod-${{ NAME }}"
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
image: python:3.7-alpine
|
||||
imagePullPolicy: Always
|
||||
name: python
|
||||
- args:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
image: python:3.7-alpine
|
||||
imagePullPolicy: Always
|
||||
name: python
|
||||
parameters:
|
||||
- name: NAME
|
||||
- name: NAME
|
||||
description: trailing name of the pod
|
||||
required: true
|
||||
|
||||
@@ -13,22 +13,22 @@ metadata:
|
||||
tags: quickstart,examples
|
||||
name: simple-example
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
description: Big example
|
||||
name: ${NAME}
|
||||
data:
|
||||
content: "${CONTENT}"
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
description: Big example
|
||||
name: ${NAME}
|
||||
data:
|
||||
content: "${CONTENT}"
|
||||
parameters:
|
||||
- description: The name assigned to the ConfigMap
|
||||
displayName: Name
|
||||
name: NAME
|
||||
required: true
|
||||
value: example
|
||||
- description: The value for the content key of the configmap
|
||||
displayName: Content
|
||||
name: CONTENT
|
||||
required: true
|
||||
value: ''
|
||||
- description: The name assigned to the ConfigMap
|
||||
displayName: Name
|
||||
name: NAME
|
||||
required: true
|
||||
value: example
|
||||
- description: The value for the content key of the configmap
|
||||
displayName: Content
|
||||
name: CONTENT
|
||||
required: true
|
||||
value: ''
|
||||
|
||||
@@ -4,7 +4,7 @@ dependency:
|
||||
options:
|
||||
requirements-file: requirements.yml
|
||||
driver:
|
||||
name: delegated
|
||||
name: default
|
||||
platforms:
|
||||
- name: cluster
|
||||
groups:
|
||||
@@ -17,9 +17,6 @@ provisioner:
|
||||
config_options:
|
||||
inventory:
|
||||
enable_plugins: community.okd.openshift
|
||||
lint: |
|
||||
set -e
|
||||
ansible-lint
|
||||
inventory:
|
||||
hosts:
|
||||
plugin: community.okd.openshift
|
||||
@@ -34,14 +31,10 @@ provisioner:
|
||||
ANSIBLE_COLLECTIONS_PATHS: ${OVERRIDE_COLLECTION_PATH:-$MOLECULE_PROJECT_DIRECTORY}
|
||||
verifier:
|
||||
name: ansible
|
||||
lint: |
|
||||
set -e
|
||||
ansible-lint
|
||||
scenario:
|
||||
name: default
|
||||
test_sequence:
|
||||
- dependency
|
||||
- lint
|
||||
- syntax
|
||||
- prepare
|
||||
- converge
|
||||
|
||||
@@ -37,12 +37,12 @@
|
||||
name: cluster
|
||||
spec:
|
||||
identityProviders:
|
||||
- name: htpasswd_provider
|
||||
mappingMethod: claim
|
||||
type: HTPasswd
|
||||
htpasswd:
|
||||
fileData:
|
||||
name: htpass-secret
|
||||
- name: htpasswd_provider
|
||||
mappingMethod: claim
|
||||
type: HTPasswd
|
||||
htpasswd:
|
||||
fileData:
|
||||
name: htpass-secret
|
||||
|
||||
- name: Create ClusterRoleBinding for test user
|
||||
community.okd.k8s:
|
||||
|
||||
@@ -89,6 +89,7 @@ def execute():
|
||||
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
connection = ldap.initialize(module.params['server_uri'])
|
||||
connection.set_option(ldap.OPT_REFERRALS, 0)
|
||||
try:
|
||||
connection.simple_bind_s(module.params['bind_dn'], module.params['bind_pw'])
|
||||
except ldap.LDAPError as e:
|
||||
|
||||
@@ -1,227 +1,227 @@
|
||||
---
|
||||
- block:
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_entries: "{{ lookup('template', 'ad/definition.j2') | from_yaml }}"
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_entries: "{{ lookup('template', 'ad/definition.j2') | from_yaml }}"
|
||||
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- admins
|
||||
- developers
|
||||
|
||||
- name: Delete existing LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_entries.users + ldap_entries.units | reverse | list }}"
|
||||
|
||||
- name: Create LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_entries.units + ldap_entries.users }}"
|
||||
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
sync_config: "{{ lookup('template', 'ad/sync-config.j2') | from_yaml }}"
|
||||
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 2
|
||||
- devs_group.users | length == 1
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
|
||||
- name: Synchronize Groups (Remove check_mode)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Read developers group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Define user dn to delete
|
||||
set_fact:
|
||||
user_to_delete: "cn=Jane,ou=engineers,ou=activeD,{{ ldap_root }}"
|
||||
|
||||
- name: Delete 1 admin user
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ user_to_delete }}"
|
||||
state: absent
|
||||
|
||||
- name: Synchronize Openshift groups using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
allow_groups:
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- admins
|
||||
- developers
|
||||
type: openshift
|
||||
register: openshift_sync
|
||||
|
||||
- name: Validate that only developers group was sync
|
||||
assert:
|
||||
that:
|
||||
- openshift_sync is changed
|
||||
- openshift_sync.groups | length == 1
|
||||
- openshift_sync.groups.0.metadata.name == "developers"
|
||||
- name: Delete existing LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_entries.users + ldap_entries.units | reverse | list }}"
|
||||
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
- name: Create LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_entries.units + ldap_entries.users }}"
|
||||
|
||||
- name: Validate admins group content has not changed
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
sync_config: "{{ lookup('template', 'ad/sync-config.j2') | from_yaml }}"
|
||||
|
||||
- name: Synchronize Openshift groups using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
deny_groups:
|
||||
- developers
|
||||
type: openshift
|
||||
register: openshift_sync
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate that only admins group was sync
|
||||
assert:
|
||||
that:
|
||||
- openshift_sync is changed
|
||||
- openshift_sync.groups | length == 1
|
||||
- openshift_sync.groups.0.metadata.name == "admins"
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 2
|
||||
- devs_group.users | length == 1
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
- name: Synchronize Groups (Remove check_mode)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
register: result
|
||||
|
||||
- name: Validate admins group contains only 1 user now
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- result.resources.0.users == ["jim.adams@ansible.org"]
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Set users to delete (delete all developers users)
|
||||
set_fact:
|
||||
user_to_delete: "cn=Jordan,ou=engineers,ou=activeD,{{ ldap_root }}"
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Delete 1 admin user
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ user_to_delete }}"
|
||||
state: absent
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: Read developers group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed (only developers group be deleted)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Get developers group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
- name: Define user dn to delete
|
||||
set_fact:
|
||||
user_to_delete: "cn=Jane,ou=engineers,ou=activeD,{{ ldap_root }}"
|
||||
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
- name: Delete 1 admin user
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ user_to_delete }}"
|
||||
state: absent
|
||||
|
||||
- name: Get admins group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
- name: Synchronize Openshift groups using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
allow_groups:
|
||||
- developers
|
||||
type: openshift
|
||||
register: openshift_sync
|
||||
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- name: Validate that only developers group was sync
|
||||
assert:
|
||||
that:
|
||||
- openshift_sync is changed
|
||||
- openshift_sync.groups | length == 1
|
||||
- openshift_sync.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Assert nothing was changed
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- name: Validate admins group content has not changed
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Synchronize Openshift groups using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
deny_groups:
|
||||
- developers
|
||||
type: openshift
|
||||
register: openshift_sync
|
||||
|
||||
- name: Validate that only admins group was sync
|
||||
assert:
|
||||
that:
|
||||
- openshift_sync is changed
|
||||
- openshift_sync.groups | length == 1
|
||||
- openshift_sync.groups.0.metadata.name == "admins"
|
||||
|
||||
- name: Read admins group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate admins group contains only 1 user now
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- result.resources.0.users == ["jim.adams@ansible.org"]
|
||||
|
||||
- name: Set users to delete (delete all developers users)
|
||||
set_fact:
|
||||
user_to_delete: "cn=Jordan,ou=engineers,ou=activeD,{{ ldap_root }}"
|
||||
|
||||
- name: Delete 1 admin user
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ user_to_delete }}"
|
||||
state: absent
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed (only developers group be deleted)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
|
||||
- name: Get developers group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
|
||||
- name: Get admins group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Assert nothing was changed
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
|
||||
always:
|
||||
- name: Delete openshift groups if existing
|
||||
|
||||
@@ -1,166 +1,165 @@
|
||||
---
|
||||
- block:
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_entries: "{{ lookup('template', 'augmented-ad/definition.j2') | from_yaml }}"
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_entries: "{{ lookup('template', 'augmented-ad/definition.j2') | from_yaml }}"
|
||||
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- banking
|
||||
- insurance
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- banking
|
||||
- insurance
|
||||
|
||||
- name: Delete existing LDAP entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_entries.users + ldap_entries.groups + ldap_entries.units | reverse | list }}"
|
||||
- name: Delete existing LDAP entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_entries.users + ldap_entries.groups + ldap_entries.units | reverse | list }}"
|
||||
|
||||
- name: Create LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_entries.units + ldap_entries.groups + ldap_entries.users }}"
|
||||
- name: Create LDAP Entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_entries.units + ldap_entries.groups + ldap_entries.users }}"
|
||||
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
sync_config: "{{ lookup('template', 'augmented-ad/sync-config.j2') | from_yaml }}"
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
sync_config: "{{ lookup('template', 'augmented-ad/sync-config.j2') | from_yaml }}"
|
||||
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate that 'banking' and 'insurance' groups were created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- banking_group
|
||||
- insurance_group
|
||||
- '"james-allan@ansible.org" in {{ banking_group.users }}'
|
||||
- '"gordon-kane@ansible.org" in {{ banking_group.users }}'
|
||||
- '"alice-courtney@ansible.org" in {{ insurance_group.users }}'
|
||||
- banking_group.users | length == 2
|
||||
- insurance_group.users | length == 1
|
||||
vars:
|
||||
banking_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'banking') | first }}"
|
||||
insurance_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'insurance') | first }}"
|
||||
- name: Validate that 'banking' and 'insurance' groups were created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- banking_group
|
||||
- insurance_group
|
||||
- '"james-allan@ansible.org" in {{ banking_group.users }}'
|
||||
- '"gordon-kane@ansible.org" in {{ banking_group.users }}'
|
||||
- '"alice-courtney@ansible.org" in {{ insurance_group.users }}'
|
||||
- banking_group.users | length == 2
|
||||
- insurance_group.users | length == 1
|
||||
vars:
|
||||
banking_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'banking') | first }}"
|
||||
insurance_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'insurance') | first }}"
|
||||
|
||||
- name: Synchronize Groups (Remove check_mode)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
register: result
|
||||
|
||||
- name: Synchronize Groups (Remove check_mode)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
register: result
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- name: Define facts for group to create
|
||||
set_fact:
|
||||
ldap_groups:
|
||||
- name: banking
|
||||
users:
|
||||
- "james-allan@ansible.org"
|
||||
- "gordon-kane@ansible.org"
|
||||
- name: insurance
|
||||
users:
|
||||
- "alice-courtney@ansible.org"
|
||||
|
||||
- name: Define facts for group to create
|
||||
set_fact:
|
||||
ldap_groups:
|
||||
- name: banking
|
||||
users:
|
||||
- "james-allan@ansible.org"
|
||||
- "gordon-kane@ansible.org"
|
||||
- name: insurance
|
||||
users:
|
||||
- "alice-courtney@ansible.org"
|
||||
- name: Read 'banking' openshift group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: banking
|
||||
register: result
|
||||
|
||||
- name: Validate group info
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"james-allan@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"gordon-kane@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Read 'banking' openshift group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: banking
|
||||
register: result
|
||||
- name: Read 'insurance' openshift group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: insurance
|
||||
register: result
|
||||
|
||||
- name: Validate group info
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"james-allan@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"gordon-kane@ansible.org" in {{ result.resources.0.users }}'
|
||||
- name: Validate group info
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- 'result.resources.0.users == ["alice-courtney@ansible.org"]'
|
||||
|
||||
- name: Read 'insurance' openshift group
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: insurance
|
||||
register: result
|
||||
- name: Delete employee from 'insurance' group
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "cn=Alice,ou=employee,ou=augmentedAD,{{ ldap_root }}"
|
||||
state: absent
|
||||
|
||||
- name: Validate group info
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- 'result.resources.0.users == ["alice-courtney@ansible.org"]'
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Delete employee from 'insurance' group
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "cn=Alice,ou=employee,ou=augmentedAD,{{ ldap_root }}"
|
||||
state: absent
|
||||
- name: Validate result is changed (only insurance group be deleted)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: Get 'insurance' openshift group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: insurance
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed (only insurance group be deleted)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
|
||||
- name: Get 'insurance' openshift group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: insurance
|
||||
register: result
|
||||
- name: Get 'banking' openshift group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: banking
|
||||
register: result
|
||||
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Get 'banking' openshift group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: banking
|
||||
register: result
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ sync_config }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Assert no change was made
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- name: Assert no change was made
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
|
||||
always:
|
||||
- name: Delete openshift groups if existing
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: Get cluster information
|
||||
- name: Get cluster information
|
||||
kubernetes.core.k8s_cluster_info:
|
||||
register: info
|
||||
|
||||
@@ -16,30 +16,29 @@
|
||||
app: ldap
|
||||
spec:
|
||||
containers:
|
||||
- name: ldap
|
||||
image: bitnami/openldap
|
||||
env:
|
||||
- name: LDAP_ADMIN_USERNAME
|
||||
value: "{{ ldap_admin_user }}"
|
||||
- name: LDAP_ADMIN_PASSWORD
|
||||
value: "{{ ldap_admin_password }}"
|
||||
- name: LDAP_USERS
|
||||
value: "ansible"
|
||||
- name: LDAP_PASSWORDS
|
||||
value: "ansible123"
|
||||
- name: LDAP_ROOT
|
||||
value: "{{ ldap_root }}"
|
||||
ports:
|
||||
- containerPort: 1389
|
||||
- name: ldap
|
||||
image: bitnami/openldap
|
||||
env:
|
||||
- name: LDAP_ADMIN_USERNAME
|
||||
value: "{{ ldap_admin_user }}"
|
||||
- name: LDAP_ADMIN_PASSWORD
|
||||
value: "{{ ldap_admin_password }}"
|
||||
- name: LDAP_USERS
|
||||
value: "ansible"
|
||||
- name: LDAP_PASSWORDS
|
||||
value: "ansible123"
|
||||
- name: LDAP_ROOT
|
||||
value: "{{ ldap_root }}"
|
||||
ports:
|
||||
- containerPort: 1389
|
||||
name: ldap-server
|
||||
register: pod_info
|
||||
|
||||
- name: Set Pod Internal IP
|
||||
set_fact:
|
||||
podIp: "{{ pod_info.result.status.podIP }}"
|
||||
|
||||
- name: Set LDAP Common facts
|
||||
set_fact:
|
||||
ldap_server_uri: "ldap://{{ podIp }}:1389"
|
||||
# we can use the Pod IP directly because the integration are running inside a Pod in the
|
||||
# same openshift cluster
|
||||
ldap_server_uri: "ldap://{{ pod_info.result.status.podIP }}:1389"
|
||||
ldap_bind_dn: "cn={{ ldap_admin_user }},{{ ldap_root }}"
|
||||
ldap_bind_pw: "{{ ldap_admin_password }}"
|
||||
|
||||
@@ -53,8 +52,10 @@
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
dn: "ou=users,{{ ldap_root }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
# ignore_errors: true
|
||||
# register: ping_ldap
|
||||
register: test_ldap
|
||||
retries: 10
|
||||
delay: 5
|
||||
until: test_ldap is not failed
|
||||
|
||||
- include_tasks: "tasks/python-ldap-not-installed.yml"
|
||||
- include_tasks: "tasks/rfc2307.yml"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- block:
|
||||
- name: Create temp directory
|
||||
tempfile:
|
||||
|
||||
@@ -1,459 +1,460 @@
|
||||
---
|
||||
- block:
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_resources: "{{ lookup('template', 'rfc2307/definition.j2') | from_yaml }}"
|
||||
- name: Get LDAP definition
|
||||
set_fact:
|
||||
ldap_resources: "{{ lookup('template', 'rfc2307/definition.j2') | from_yaml }}"
|
||||
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- admins
|
||||
- engineers
|
||||
- developers
|
||||
|
||||
- name: Delete existing LDAP entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_resources.users + ldap_resources.groups + ldap_resources.units | reverse | list }}"
|
||||
|
||||
- name: Create LDAP units
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.units }}"
|
||||
|
||||
- name: Create LDAP Groups
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.groups }}"
|
||||
|
||||
- name: Create LDAP users
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.users }}"
|
||||
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
configs: "{{ lookup('template', 'rfc2307/sync-config.j2') | from_yaml }}"
|
||||
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
- name: Synchronize Groups - User defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.user_defined }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-devs') | first }}"
|
||||
|
||||
- name: Synchronize Groups - Using dn for every query
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.dn_everywhere }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ admins_group.users }}'
|
||||
- '"cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}'
|
||||
- '"cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=admins,ou=groups,ou=rfc2307,' + ldap_root ) | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=developers,ou=groups,ou=rfc2307,' + ldap_root ) | first }}"
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.partially_user_defined }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
- name: Delete Group 'engineers' if created before
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: 'engineers'
|
||||
wait: yes
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.out_scope }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Assert group sync failed due to non-existent member
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- result.msg.startswith("Entry not found for base='cn=Matthew,ou=people,ou=outrfc2307,{{ ldap_root }}'")
|
||||
|
||||
- name: Define sync configuration with tolerateMemberNotFoundErrors
|
||||
set_fact:
|
||||
config_out_of_scope_tolerate_not_found: "{{ configs.out_scope | combine({'rfc2307': merge_rfc2307 })}}"
|
||||
vars:
|
||||
merge_rfc2307: "{{ configs.out_scope.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}"
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping (tolerateMemberNotFoundErrors=true)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_out_of_scope_tolerate_not_found }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Assert group sync did not fail (tolerateMemberNotFoundErrors=true)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == 'engineers'
|
||||
- result.groups.0.users == ['Abraham']
|
||||
|
||||
- name: Create Group 'engineers'
|
||||
community.okd.k8s:
|
||||
state: present
|
||||
wait: yes
|
||||
definition:
|
||||
- name: Delete openshift groups if existing
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
apiVersion: "user.openshift.io/v1"
|
||||
metadata:
|
||||
name: engineers
|
||||
users: []
|
||||
|
||||
- name: Try to sync LDAP group with Openshift existing group not created using sync should failed
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_out_of_scope_tolerate_not_found }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Validate group sync failed
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- '"openshift.io/ldap.host label did not match sync host" in result.msg'
|
||||
|
||||
- name: Define allow_groups and deny_groups groups
|
||||
set_fact:
|
||||
allow_groups:
|
||||
- "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
deny_groups:
|
||||
- "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Synchronize Groups using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
allow_groups: "{{ allow_groups }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Synchronize Groups using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
deny_groups: "{{ deny_groups }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Synchronize groups, remove check_mode
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Set users to delete (no admins users anymore and only 1 developer kept)
|
||||
set_fact:
|
||||
users_to_delete:
|
||||
- "cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}"
|
||||
- "cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Delete users from LDAP servers
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ users_to_delete }}"
|
||||
|
||||
- name: Define sync configuration with tolerateMemberNotFoundErrors
|
||||
set_fact:
|
||||
config_simple_tolerate_not_found: "{{ configs.simple | combine({'rfc2307': merge_rfc2307 })}}"
|
||||
vars:
|
||||
merge_rfc2307: "{{ configs.simple.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}"
|
||||
|
||||
- name: Synchronize groups once again after users deletion
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate admins group does not contains users anymore
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- result.resources.0.users == []
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Set group to delete
|
||||
set_fact:
|
||||
groups_to_delete:
|
||||
- "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Delete Group from LDAP servers
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ groups_to_delete }}"
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate that only developers group is candidate for Prune
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Read Group (validate that check_mode did not performed update in the cluster)
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Assert group was found
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Prune using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
allow_groups:
|
||||
version: "user.openshift.io/v1"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- admins
|
||||
- engineers
|
||||
- developers
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: assert developers group was candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
- name: Delete existing LDAP entries
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
state: absent
|
||||
with_items: "{{ ldap_resources.users + ldap_resources.groups + ldap_resources.units | reverse | list }}"
|
||||
|
||||
- name: Prune using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
deny_groups:
|
||||
- developers
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
- name: Create LDAP units
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.units }}"
|
||||
|
||||
- name: assert nothing found candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.groups | length == 0
|
||||
- name: Create LDAP Groups
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.groups }}"
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: Create LDAP users
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item.dn }}"
|
||||
attributes: "{{ item.attr }}"
|
||||
objectClass: "{{ item.class }}"
|
||||
with_items: "{{ ldap_resources.users }}"
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- name: Load test configurations
|
||||
set_fact:
|
||||
configs: "{{ lookup('template', 'rfc2307/sync-config.j2') | from_yaml }}"
|
||||
|
||||
- name: Get developers group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
- name: Synchronize Groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
- name: Get admins group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
- name: Synchronize Groups - User defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.user_defined }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-devs') | first }}"
|
||||
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: Synchronize Groups - Using dn for every query
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.dn_everywhere }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Assert nothing changed
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.groups | length == 0
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ admins_group.users }}'
|
||||
- '"cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}'
|
||||
- '"cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=admins,ou=groups,ou=rfc2307,' + ldap_root ) | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=developers,ou=groups,ou=rfc2307,' + ldap_root ) | first }}"
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.partially_user_defined }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- admins_group
|
||||
- devs_group
|
||||
- '"jane.smith@ansible.org" in {{ admins_group.users }}'
|
||||
- '"jim.adams@ansible.org" in {{ devs_group.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ devs_group.users }}'
|
||||
- admins_group.users | length == 1
|
||||
- devs_group.users | length == 2
|
||||
vars:
|
||||
admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}"
|
||||
devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}"
|
||||
|
||||
- name: Delete Group 'engineers' if created before
|
||||
community.okd.k8s:
|
||||
state: absent
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: 'engineers'
|
||||
wait: yes
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.out_scope }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Assert group sync failed due to non-existent member
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- result.msg.startswith("Entry not found for base='cn=Matthew,ou=people,ou=outrfc2307,{{ ldap_root }}'")
|
||||
|
||||
- name: Define sync configuration with tolerateMemberNotFoundErrors
|
||||
set_fact:
|
||||
config_out_of_scope_tolerate_not_found: "{{ configs.out_scope | combine({'rfc2307': merge_rfc2307 })}}"
|
||||
vars:
|
||||
merge_rfc2307: "{{ configs.out_scope.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}"
|
||||
|
||||
- name: Synchronize Groups - Partially user defined mapping (tolerateMemberNotFoundErrors=true)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_out_of_scope_tolerate_not_found }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
|
||||
- name: Assert group sync did not fail (tolerateMemberNotFoundErrors=true)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == 'engineers'
|
||||
- result.groups.0.users == ['Abraham']
|
||||
|
||||
- name: Create Group 'engineers'
|
||||
community.okd.k8s:
|
||||
state: present
|
||||
wait: yes
|
||||
definition:
|
||||
kind: Group
|
||||
apiVersion: "user.openshift.io/v1"
|
||||
metadata:
|
||||
name: engineers
|
||||
users: []
|
||||
|
||||
- name: Try to sync LDAP group with Openshift existing group not created using sync should failed
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_out_of_scope_tolerate_not_found }}"
|
||||
check_mode: yes
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Validate group sync failed
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- '"openshift.io/ldap.host label did not match sync host" in result.msg'
|
||||
|
||||
- name: Define allow_groups and deny_groups groups
|
||||
set_fact:
|
||||
allow_groups:
|
||||
- "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
deny_groups:
|
||||
- "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Synchronize Groups using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
allow_groups: "{{ allow_groups }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Synchronize Groups using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
deny_groups: "{{ deny_groups }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate Group going to be created
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Synchronize groups, remove check_mode
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ configs.simple }}"
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jane.smith@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jim.adams@ansible.org" in {{ result.resources.0.users }}'
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Set users to delete (no admins users anymore and only 1 developer kept)
|
||||
set_fact:
|
||||
users_to_delete:
|
||||
- "cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}"
|
||||
- "cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Delete users from LDAP servers
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ users_to_delete }}"
|
||||
|
||||
- name: Define sync configuration with tolerateMemberNotFoundErrors
|
||||
set_fact:
|
||||
config_simple_tolerate_not_found: "{{ configs.simple | combine({'rfc2307': merge_rfc2307 })}}"
|
||||
vars:
|
||||
merge_rfc2307: "{{ configs.simple.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}"
|
||||
|
||||
- name: Synchronize groups once again after users deletion
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: Validate admins group does not contains users anymore
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- result.resources.0.users == []
|
||||
|
||||
- name: Read Groups
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Validate group was created
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
- '"jordanbulls@ansible.org" in {{ result.resources.0.users }}'
|
||||
|
||||
- name: Set group to delete
|
||||
set_fact:
|
||||
groups_to_delete:
|
||||
- "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}"
|
||||
|
||||
- name: Delete Group from LDAP servers
|
||||
openshift_ldap_entry:
|
||||
bind_dn: "{{ ldap_bind_dn }}"
|
||||
bind_pw: "{{ ldap_bind_pw }}"
|
||||
server_uri: "{{ ldap_server_uri }}"
|
||||
dn: "{{ item }}"
|
||||
state: absent
|
||||
with_items: "{{ groups_to_delete }}"
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: Validate that only developers group is candidate for Prune
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Read Group (validate that check_mode did not performed update in the cluster)
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: Assert group was found
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Prune using allow_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
allow_groups:
|
||||
- developers
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: assert developers group was candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
- result.groups.0.metadata.name == "developers"
|
||||
|
||||
- name: Prune using deny_groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
deny_groups:
|
||||
- developers
|
||||
state: absent
|
||||
register: result
|
||||
check_mode: yes
|
||||
|
||||
- name: assert nothing found candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.groups | length == 0
|
||||
|
||||
- name: Prune groups
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Validate result is changed
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.groups | length == 1
|
||||
|
||||
- name: Get developers group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: developers
|
||||
register: result
|
||||
|
||||
- name: assert group was deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 0
|
||||
|
||||
- name: Get admins group info
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Group
|
||||
version: "user.openshift.io/v1"
|
||||
name: admins
|
||||
register: result
|
||||
|
||||
- name: assert group was not deleted
|
||||
assert:
|
||||
that:
|
||||
- result.resources | length == 1
|
||||
|
||||
- name: Prune groups once again (idempotency)
|
||||
community.okd.openshift_adm_groups_sync:
|
||||
config: "{{ config_simple_tolerate_not_found }}"
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: Assert nothing changed
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.groups | length == 0
|
||||
|
||||
always:
|
||||
- name: Delete openshift groups if existing
|
||||
|
||||
@@ -1,293 +1,294 @@
|
||||
---
|
||||
- block:
|
||||
- set_fact:
|
||||
test_sa: "clusterrole-sa"
|
||||
test_ns: "clusterrole-ns"
|
||||
- set_fact:
|
||||
test_sa: "clusterrole-sa"
|
||||
test_ns: "clusterrole-ns"
|
||||
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: "{{ test_ns }}"
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: "{{ test_ns }}"
|
||||
|
||||
- name: Get cluster information
|
||||
kubernetes.core.k8s_cluster_info:
|
||||
register: cluster_info
|
||||
no_log: true
|
||||
- name: Get cluster information
|
||||
kubernetes.core.k8s_cluster_info:
|
||||
register: cluster_info
|
||||
no_log: true
|
||||
|
||||
- set_fact:
|
||||
cluster_host: "{{ cluster_info['connection']['host'] }}"
|
||||
- set_fact:
|
||||
cluster_host: "{{ cluster_info['connection']['host'] }}"
|
||||
|
||||
- name: Create Service account
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
- name: Create Service account
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
|
||||
- name: Read Service Account
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ test_sa }}"
|
||||
register: result
|
||||
|
||||
- name: Read Service Account
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ServiceAccount
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ test_sa }}"
|
||||
register: result
|
||||
- set_fact:
|
||||
secret_token: "{{ result.resources[0]['secrets'][0]['name'] }}"
|
||||
|
||||
- set_fact:
|
||||
secret_token: "{{ result.resources[0]['secrets'][0]['name'] }}"
|
||||
- name: Get secret details
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ secret_token }}'
|
||||
register: _secret
|
||||
retries: 10
|
||||
delay: 10
|
||||
until:
|
||||
- ("'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']") or ("'token' in _secret.resources[0]['data']")
|
||||
|
||||
- name: Get secret details
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ secret_token }}'
|
||||
register: _secret
|
||||
retries: 10
|
||||
delay: 10
|
||||
until:
|
||||
- ("'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']") or ("'token' in _secret.resources[0]['data']")
|
||||
- set_fact:
|
||||
api_token: "{{ _secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}"
|
||||
when: "'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']"
|
||||
|
||||
- set_fact:
|
||||
api_token: "{{ _secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}"
|
||||
when: "'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']"
|
||||
- set_fact:
|
||||
api_token: "{{ _secret.resources[0]['data']['token'] | b64decode }}"
|
||||
when: "'token' in _secret.resources[0]['data']"
|
||||
|
||||
- set_fact:
|
||||
api_token: "{{ _secret.resources[0]['data']['token'] | b64decode }}"
|
||||
when: "'token' in _secret.resources[0]['data']"
|
||||
- name: list Node should failed (forbidden user)
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Node should failed (forbidden user)
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
register: error
|
||||
ignore_errors: true
|
||||
- assert:
|
||||
that:
|
||||
- '"nodes is forbidden: User" in error.msg'
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"nodes is forbidden: User" in error.msg'
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
ignore_errors: true
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- name: list Pod for test namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Pod for test namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
ignore_errors: true
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- set_fact:
|
||||
test_labels:
|
||||
phase: dev
|
||||
cluster_roles:
|
||||
- name: pod-manager
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- list
|
||||
api_version_binding: "authorization.openshift.io/v1"
|
||||
- name: node-manager
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- list
|
||||
api_version_binding: "rbac.authorization.k8s.io/v1"
|
||||
|
||||
- set_fact:
|
||||
test_labels:
|
||||
phase: dev
|
||||
cluster_roles:
|
||||
- name: pod-manager
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- list
|
||||
api_version_binding: "authorization.openshift.io/v1"
|
||||
- name: node-manager
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- list
|
||||
api_version_binding: "rbac.authorization.k8s.io/v1"
|
||||
|
||||
- name: Create cluster roles
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: ClusterRole
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
metadata:
|
||||
name: "{{ item.name }}"
|
||||
labels: "{{ test_labels }}"
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: "{{ item.resources }}"
|
||||
verbs: "{{ item.verbs }}"
|
||||
with_items: '{{ cluster_roles }}'
|
||||
|
||||
- name: Create Role Binding (namespaced)
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: RoleBinding
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
metadata:
|
||||
name: "{{ cluster_roles[0].name }}-binding"
|
||||
namespace: "{{ test_ns }}"
|
||||
labels: "{{ test_labels }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
- name: Create cluster roles
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: ClusterRole
|
||||
name: "{{ cluster_roles[0].name }}"
|
||||
apiGroup: ""
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
metadata:
|
||||
name: "{{ item.name }}"
|
||||
labels: "{{ test_labels }}"
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: "{{ item.resources }}"
|
||||
verbs: "{{ item.verbs }}"
|
||||
with_items: '{{ cluster_roles }}'
|
||||
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
ignore_errors: true
|
||||
- name: Create Role Binding (namespaced)
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: RoleBinding
|
||||
apiVersion: "rbac.authorization.k8s.io/v1"
|
||||
metadata:
|
||||
name: "{{ cluster_roles[0].name }}-binding"
|
||||
namespace: "{{ test_ns }}"
|
||||
labels: "{{ test_labels }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: "{{ cluster_roles[0].name }}"
|
||||
apiGroup: ""
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Pod for test namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- name: Create Cluster role Binding
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: "{{ item.api_version_binding }}"
|
||||
metadata:
|
||||
name: "{{ item.name }}-binding"
|
||||
labels: "{{ test_labels }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: "{{ item.name }}"
|
||||
apiGroup: ""
|
||||
with_items: "{{ cluster_roles }}"
|
||||
- name: list Pod for test namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
|
||||
- name: list Pod for all namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
no_log: true
|
||||
- name: Create Cluster role Binding
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: "{{ item.api_version_binding }}"
|
||||
metadata:
|
||||
name: "{{ item.name }}-binding"
|
||||
labels: "{{ test_labels }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ test_sa }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: "{{ item.name }}"
|
||||
apiGroup: ""
|
||||
with_items: "{{ cluster_roles }}"
|
||||
|
||||
- name: list Pod for test namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
- name: list Pod for all namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
no_log: true
|
||||
|
||||
- name: list Node using ServiceAccount
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
- name: list Pod for test namespace should succeed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
|
||||
- name: Prune clusterroles (check mode)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
label_selectors:
|
||||
- phase=dev
|
||||
register: check
|
||||
check_mode: true
|
||||
- name: list Node using ServiceAccount
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
|
||||
- name: validate clusterrole binding candidates for prune
|
||||
assert:
|
||||
that:
|
||||
- '"{{ item.name }}-binding" in check.cluster_role_binding'
|
||||
- '"{{ test_ns }}/{{ cluster_roles[0].name }}-binding" in check.role_binding'
|
||||
with_items: "{{ cluster_roles }}"
|
||||
- name: Prune clusterroles (check mode)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
label_selectors:
|
||||
- phase=dev
|
||||
register: check
|
||||
check_mode: true
|
||||
|
||||
- name: Prune Cluster Role for managing Pod
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
name: "{{ cluster_roles[0].name }}"
|
||||
- name: validate clusterrole binding candidates for prune
|
||||
assert:
|
||||
that:
|
||||
- '"{{ item.name }}-binding" in check.cluster_role_binding'
|
||||
- '"{{ test_ns }}/{{ cluster_roles[0].name }}-binding" in check.role_binding'
|
||||
with_items: "{{ cluster_roles }}"
|
||||
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
no_log: true
|
||||
ignore_errors: true
|
||||
- name: Prune Cluster Role for managing Pod
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
name: "{{ cluster_roles[0].name }}"
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- name: list Pod for all namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
register: error
|
||||
no_log: true
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Pod for test namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
no_log: true
|
||||
ignore_errors: true
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- name: list Pod for test namespace should failed
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
no_log: true
|
||||
ignore_errors: true
|
||||
|
||||
- name: list Node using ServiceAccount
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- name: Prune clusterroles (remaining)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
label_selectors:
|
||||
- phase=dev
|
||||
- name: list Node using ServiceAccount
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
no_log: true
|
||||
|
||||
- name: list Node using ServiceAccount should fail
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
ignore_errors: true
|
||||
- name: Prune clusterroles (remaining)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: clusterroles
|
||||
label_selectors:
|
||||
- phase=dev
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"nodes is forbidden: User" in error.msg'
|
||||
- name: list Node using ServiceAccount should fail
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
kind: Node
|
||||
namespace: "{{ test_ns }}"
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"nodes is forbidden: User" in error.msg'
|
||||
|
||||
always:
|
||||
- name: Ensure namespace is deleted
|
||||
|
||||
@@ -1,335 +1,336 @@
|
||||
---
|
||||
- block:
|
||||
- set_fact:
|
||||
test_ns: "prune-roles"
|
||||
sa_name: "roles-sa"
|
||||
pod_name: "pod-prune"
|
||||
role_definition:
|
||||
- name: pod-list
|
||||
labels:
|
||||
action: list
|
||||
verbs:
|
||||
- list
|
||||
role_binding:
|
||||
api_version: rbac.authorization.k8s.io/v1
|
||||
- name: pod-create
|
||||
labels:
|
||||
action: create
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
role_binding:
|
||||
api_version: authorization.openshift.io/v1
|
||||
- name: pod-delete
|
||||
labels:
|
||||
action: delete
|
||||
verbs:
|
||||
- delete
|
||||
role_binding:
|
||||
api_version: rbac.authorization.k8s.io/v1
|
||||
- set_fact:
|
||||
test_ns: "prune-roles"
|
||||
sa_name: "roles-sa"
|
||||
pod_name: "pod-prune"
|
||||
role_definition:
|
||||
- name: pod-list
|
||||
labels:
|
||||
action: list
|
||||
verbs:
|
||||
- list
|
||||
role_binding:
|
||||
api_version: rbac.authorization.k8s.io/v1
|
||||
- name: pod-create
|
||||
labels:
|
||||
action: create
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
role_binding:
|
||||
api_version: authorization.openshift.io/v1
|
||||
- name: pod-delete
|
||||
labels:
|
||||
action: delete
|
||||
verbs:
|
||||
- delete
|
||||
role_binding:
|
||||
api_version: rbac.authorization.k8s.io/v1
|
||||
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ test_ns }}'
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ test_ns }}'
|
||||
|
||||
- name: Get cluster information
|
||||
kubernetes.core.k8s_cluster_info:
|
||||
register: cluster_info
|
||||
no_log: true
|
||||
- name: Get cluster information
|
||||
kubernetes.core.k8s_cluster_info:
|
||||
register: cluster_info
|
||||
no_log: true
|
||||
|
||||
- set_fact:
|
||||
cluster_host: "{{ cluster_info['connection']['host'] }}"
|
||||
- set_fact:
|
||||
cluster_host: "{{ cluster_info['connection']['host'] }}"
|
||||
|
||||
- name: Create Service account
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
- name: Create Service account
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: '{{ sa_name }}'
|
||||
namespace: '{{ test_ns }}'
|
||||
|
||||
- name: Read Service Account
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: '{{ sa_name }}'
|
||||
namespace: '{{ test_ns }}'
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ sa_name }}'
|
||||
register: sa_out
|
||||
|
||||
- name: Read Service Account
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ServiceAccount
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ sa_name }}'
|
||||
register: sa_out
|
||||
- set_fact:
|
||||
secret_token: "{{ sa_out.resources[0]['secrets'][0]['name'] }}"
|
||||
|
||||
- set_fact:
|
||||
secret_token: "{{ sa_out.resources[0]['secrets'][0]['name'] }}"
|
||||
- name: Get secret details
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ secret_token }}'
|
||||
register: r_secret
|
||||
retries: 10
|
||||
delay: 10
|
||||
until:
|
||||
- ("'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']") or ("'token' in r_secret.resources[0]['data']")
|
||||
|
||||
- name: Get secret details
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Secret
|
||||
namespace: '{{ test_ns }}'
|
||||
name: '{{ secret_token }}'
|
||||
register: r_secret
|
||||
retries: 10
|
||||
delay: 10
|
||||
until:
|
||||
- ("'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']") or ("'token' in r_secret.resources[0]['data']")
|
||||
- set_fact:
|
||||
api_token: "{{ r_secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}"
|
||||
when: "'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']"
|
||||
|
||||
- set_fact:
|
||||
api_token: "{{ r_secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}"
|
||||
when: "'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']"
|
||||
|
||||
- set_fact:
|
||||
api_token: "{{ r_secret.resources[0]['data']['token'] | b64decode }}"
|
||||
when: "'token' in r_secret.resources[0]['data']"
|
||||
- set_fact:
|
||||
api_token: "{{ r_secret.resources[0]['data']['token'] | b64decode }}"
|
||||
when: "'token' in r_secret.resources[0]['data']"
|
||||
|
||||
- name: list resources using service account
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: '{{ api_token }}'
|
||||
host: '{{ cluster_host }}'
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: '{{ test_ns }}'
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
- name: list resources using service account
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: '{{ api_token }}'
|
||||
host: '{{ cluster_host }}'
|
||||
validate_certs: no
|
||||
kind: Pod
|
||||
namespace: '{{ test_ns }}'
|
||||
register: error
|
||||
ignore_errors: true
|
||||
|
||||
- name: Create a role to manage Pod from namespace "{{ test_ns }}"
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ item.name }}"
|
||||
labels: "{{ item.labels }}"
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: "{{ item.verbs }}"
|
||||
with_items: "{{ role_definition }}"
|
||||
- assert:
|
||||
that:
|
||||
- '"pods is forbidden: User" in error.msg'
|
||||
|
||||
- name: Create Role Binding
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: RoleBinding
|
||||
apiVersion: "{{ item.role_binding.api_version }}"
|
||||
metadata:
|
||||
name: "{{ item.name }}-bind"
|
||||
namespace: "{{ test_ns }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ sa_name }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
- name: Create a role to manage Pod from namespace "{{ test_ns }}"
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: Role
|
||||
name: "{{ item.name }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
with_items: "{{ role_definition }}"
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ item.name }}"
|
||||
labels: "{{ item.labels }}"
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: "{{ item.verbs }}"
|
||||
with_items: "{{ role_definition }}"
|
||||
|
||||
- name: Create Pod should succeed
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
- name: Create Role Binding
|
||||
kubernetes.core.k8s:
|
||||
definition:
|
||||
kind: RoleBinding
|
||||
apiVersion: "{{ item.role_binding.api_version }}"
|
||||
metadata:
|
||||
name: "{{ item.name }}-bind"
|
||||
namespace: "{{ test_ns }}"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "{{ sa_name }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: "{{ item.name }}"
|
||||
namespace: "{{ test_ns }}"
|
||||
apiGroup: ""
|
||||
with_items: "{{ role_definition }}"
|
||||
|
||||
- name: Create Pod should succeed
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
|
||||
- name: assert pod creation succeed
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
register: result
|
||||
|
||||
- name: assert pod creation succeed
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
- name: assert user is still authorize to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
- name: Prune auth roles (check mode)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
register: check
|
||||
check_mode: true
|
||||
|
||||
- name: assert user is still authorize to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
- name: validate that list role binding are candidates for prune
|
||||
assert:
|
||||
that: '"{{ test_ns }}/{{ item.name }}-bind" in check.role_binding'
|
||||
with_items: "{{ role_definition }}"
|
||||
|
||||
- name: Prune auth roles (check mode)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
register: check
|
||||
check_mode: true
|
||||
- name: Prune resource using label_selectors option
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
label_selectors:
|
||||
- action=delete
|
||||
register: prune
|
||||
|
||||
- name: validate that list role binding are candidates for prune
|
||||
assert:
|
||||
that: '"{{ test_ns }}/{{ item.name }}-bind" in check.role_binding'
|
||||
with_items: "{{ role_definition }}"
|
||||
- name: assert that role binding 'delete' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[2].name }}-bind" in check.role_binding'
|
||||
|
||||
- name: Prune resource using label_selectors option
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
label_selectors:
|
||||
- action=delete
|
||||
register: prune
|
||||
|
||||
- name: assert that role binding 'delete' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[2].name }}-bind" in check.role_binding'
|
||||
|
||||
- name: assert that user could not delete pod anymore
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
state: absent
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
name: "{{ pod_name }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert pod deletion failed due to forbidden user
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
|
||||
- name: assert user is still able to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: Create Pod should succeed
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
- name: assert that user could not delete pod anymore
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
state: absent
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}-1"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
name: "{{ pod_name }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert user is still authorize to create pod
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
- name: assert pod deletion failed due to forbidden user
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
|
||||
- name: Prune role using name
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ role_definition[1].name }}"
|
||||
register: prune
|
||||
|
||||
- name: assert that role binding 'create' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[1].name }}-bind" in check.role_binding'
|
||||
|
||||
- name: Create Pod (should failed)
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}-2"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
ignore_errors: true
|
||||
register: result
|
||||
|
||||
- name: assert user is not authorize to create pod anymore
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
- name: assert user is still able to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
- name: Create Pod should succeed
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}-1"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
|
||||
- name: assert user is still able to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
- name: assert user is still authorize to create pod
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: Prune all role for namespace (neither name nor label_selectors are specified)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
register: prune
|
||||
- name: Prune role using name
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "{{ role_definition[1].name }}"
|
||||
register: prune
|
||||
|
||||
- name: assert that role binding 'list' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[0].name }}-bind" in check.role_binding'
|
||||
- name: assert that role binding 'create' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[1].name }}-bind" in check.role_binding'
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
ignore_errors: true
|
||||
- name: Create Pod (should failed)
|
||||
kubernetes.core.k8s:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
definition:
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ pod_name }}-2"
|
||||
spec:
|
||||
containers:
|
||||
- name: python
|
||||
image: python:3.7-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true; do echo $(date); sleep 15; done
|
||||
imagePullPolicy: IfNotPresent
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert user is not authorize to list pod anymore
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
- name: assert user is not authorize to create pod anymore
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
|
||||
- name: assert user is still able to list pods
|
||||
assert:
|
||||
that:
|
||||
- result is successful
|
||||
|
||||
- name: Prune all role for namespace (neither name nor label_selectors are specified)
|
||||
community.okd.openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
namespace: "{{ test_ns }}"
|
||||
register: prune
|
||||
|
||||
- name: assert that role binding 'list' was pruned
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- '"{{ test_ns }}/{{ role_definition[0].name }}-bind" in check.role_binding'
|
||||
|
||||
- name: List Pod
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ api_token }}"
|
||||
host: "{{ cluster_host }}"
|
||||
validate_certs: no
|
||||
namespace: "{{ test_ns }}"
|
||||
kind: Pod
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert user is not authorize to list pod anymore
|
||||
assert:
|
||||
that:
|
||||
- '"forbidden: User" in error.msg'
|
||||
|
||||
always:
|
||||
- name: Ensure namespace is deleted
|
||||
|
||||
@@ -1,255 +1,255 @@
|
||||
---
|
||||
- name: Prune deployments
|
||||
block:
|
||||
- set_fact:
|
||||
dc_name: "hello"
|
||||
deployment_ns: "prune-deployments"
|
||||
deployment_ns_2: "prune-deployments-2"
|
||||
|
||||
- set_fact:
|
||||
dc_name: "hello"
|
||||
deployment_ns: "prune-deployments"
|
||||
deployment_ns_2: "prune-deployments-2"
|
||||
|
||||
- name: Ensure namespace
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ deployment_ns }}'
|
||||
- name: Ensure namespace
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ deployment_ns }}'
|
||||
|
||||
- name: Create deployment config
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}'
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
- name: Create deployment config
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
name: '{{ dc_name }}'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
|
||||
- name: prune deployments (no candidate DeploymentConfig)
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: test_prune
|
||||
- name: prune deployments (no candidate DeploymentConfig)
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: test_prune
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- test_prune is not changed
|
||||
- test_prune.replication_controllers | length == 0
|
||||
- assert:
|
||||
that:
|
||||
- test_prune is not changed
|
||||
- test_prune.replication_controllers | length == 0
|
||||
|
||||
- name: Update DeploymentConfig - set replicas to 0
|
||||
community.okd.k8s:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: "apps.openshift.io/v1"
|
||||
metadata:
|
||||
name: "{{ dc_name }}"
|
||||
spec:
|
||||
replicas: 0
|
||||
selector:
|
||||
- name: Update DeploymentConfig - set replicas to 0
|
||||
community.okd.k8s:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: "apps.openshift.io/v1"
|
||||
metadata:
|
||||
name: "{{ dc_name }}"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: "{{ dc_name }}"
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
spec:
|
||||
replicas: 0
|
||||
selector:
|
||||
name: "{{ dc_name }}"
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: "{{ dc_name }}"
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
|
||||
- name: Wait for ReplicationController candidate for pruning
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: result
|
||||
retries: 10
|
||||
delay: 30
|
||||
until:
|
||||
- result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete")
|
||||
- name: Wait for ReplicationController candidate for pruning
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: result
|
||||
retries: 10
|
||||
delay: 30
|
||||
until:
|
||||
- result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete")
|
||||
|
||||
- name: Prune deployments - should delete 1 ReplicationController
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
check_mode: yes
|
||||
register: test_prune
|
||||
- name: Prune deployments - should delete 1 ReplicationController
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns }}"
|
||||
check_mode: yes
|
||||
register: test_prune
|
||||
|
||||
- name: Read ReplicationController
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: replications
|
||||
- name: Read ReplicationController
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: replications
|
||||
|
||||
- name: Assert that Replication controller was not deleted
|
||||
assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
- 'replications.resources.0.metadata.name is match("{{ dc_name }}-*")'
|
||||
- name: Assert that Replication controller was not deleted
|
||||
assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
- 'replications.resources.0.metadata.name is match("{{ dc_name }}-*")'
|
||||
|
||||
- name: Assure that candidate ReplicationController was found for pruning
|
||||
assert:
|
||||
that:
|
||||
- test_prune is changed
|
||||
- test_prune.replication_controllers | length == 1
|
||||
- test_prune.replication_controllers.0.metadata.name == replications.resources.0.metadata.name
|
||||
- test_prune.replication_controllers.0.metadata.namespace == replications.resources.0.metadata.namespace
|
||||
- name: Assure that candidate ReplicationController was found for pruning
|
||||
assert:
|
||||
that:
|
||||
- test_prune is changed
|
||||
- test_prune.replication_controllers | length == 1
|
||||
- test_prune.replication_controllers.0.metadata.name == replications.resources.0.metadata.name
|
||||
- test_prune.replication_controllers.0.metadata.namespace == replications.resources.0.metadata.namespace
|
||||
|
||||
- name: Prune deployments - keep younger than 45min (check_mode)
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
keep_younger_than: 45
|
||||
namespace: "{{ deployment_ns }}"
|
||||
check_mode: true
|
||||
register: keep_younger
|
||||
- name: Prune deployments - keep younger than 45min (check_mode)
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
keep_younger_than: 45
|
||||
namespace: "{{ deployment_ns }}"
|
||||
check_mode: true
|
||||
register: keep_younger
|
||||
|
||||
- name: assert no candidate was found
|
||||
assert:
|
||||
that:
|
||||
- keep_younger is not changed
|
||||
- keep_younger.replication_controllers == []
|
||||
- name: assert no candidate was found
|
||||
assert:
|
||||
that:
|
||||
- keep_younger is not changed
|
||||
- keep_younger.replication_controllers == []
|
||||
|
||||
- name: Ensure second namespace is created
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ deployment_ns_2 }}'
|
||||
- name: Ensure second namespace is created
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ deployment_ns_2 }}'
|
||||
|
||||
- name: Create deployment config from 2nd namespace
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns_2 }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
- name: Create deployment config from 2nd namespace
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns_2 }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}2'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
name: '{{ dc_name }}2'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
|
||||
- name: Stop deployment config - replicas = 0
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns_2 }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
replicas: 0
|
||||
selector:
|
||||
- name: Stop deployment config - replicas = 0
|
||||
community.okd.k8s:
|
||||
namespace: '{{ deployment_ns_2 }}'
|
||||
definition:
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: '{{ dc_name }}2'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
spec:
|
||||
replicas: 0
|
||||
selector:
|
||||
name: '{{ dc_name }}2'
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: '{{ dc_name }}2'
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-openshift
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: python:3.7-alpine
|
||||
command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"]
|
||||
wait: yes
|
||||
|
||||
- name: Wait for ReplicationController candidate for pruning
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: result
|
||||
retries: 10
|
||||
delay: 30
|
||||
until:
|
||||
- result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete")
|
||||
- name: Wait for ReplicationController candidate for pruning
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: result
|
||||
retries: 10
|
||||
delay: 30
|
||||
until:
|
||||
- result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete")
|
||||
|
||||
# Prune from one namespace should not have any effect on others namespaces
|
||||
- name: Prune deployments from 2nd namespace
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
check_mode: yes
|
||||
register: test_prune
|
||||
# Prune from one namespace should not have any effect on others namespaces
|
||||
- name: Prune deployments from 2nd namespace
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
check_mode: yes
|
||||
register: test_prune
|
||||
|
||||
- name: Assure that candidate ReplicationController was found for pruning
|
||||
assert:
|
||||
that:
|
||||
- test_prune is changed
|
||||
- test_prune.replication_controllers | length == 1
|
||||
- "test_prune.replication_controllers.0.metadata.namespace == deployment_ns_2"
|
||||
- name: Assure that candidate ReplicationController was found for pruning
|
||||
assert:
|
||||
that:
|
||||
- test_prune is changed
|
||||
- test_prune.replication_controllers | length == 1
|
||||
- "test_prune.replication_controllers.0.metadata.namespace == deployment_ns_2"
|
||||
|
||||
# Prune without namespace option
|
||||
- name: Prune from all namespace should update more deployments
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
check_mode: yes
|
||||
register: no_namespace_prune
|
||||
# Prune without namespace option
|
||||
- name: Prune from all namespace should update more deployments
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
check_mode: yes
|
||||
register: no_namespace_prune
|
||||
|
||||
- name: Assure multiple ReplicationController were found for pruning
|
||||
assert:
|
||||
that:
|
||||
- no_namespace_prune is changed
|
||||
- no_namespace_prune.replication_controllers | length == 2
|
||||
|
||||
# Execute Prune from 2nd namespace
|
||||
- name: Read ReplicationController before Prune operation
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: replications
|
||||
- name: Assure multiple ReplicationController were found for pruning
|
||||
assert:
|
||||
that:
|
||||
- no_namespace_prune is changed
|
||||
- no_namespace_prune.replication_controllers | length == 2
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
# Execute Prune from 2nd namespace
|
||||
- name: Read ReplicationController before Prune operation
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: replications
|
||||
|
||||
- name: Prune DeploymentConfig from 2nd namespace
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: _prune
|
||||
- assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
|
||||
- name: Assert DeploymentConfig was deleted
|
||||
assert:
|
||||
that:
|
||||
- _prune is changed
|
||||
- _prune.replication_controllers | length == 1
|
||||
- _prune.replication_controllers.0.details.name == replications.resources.0.metadata.name
|
||||
- name: Prune DeploymentConfig from 2nd namespace
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: "{{ deployment_ns_2 }}"
|
||||
register: _prune
|
||||
|
||||
# Execute Prune without namespace option
|
||||
- name: Read ReplicationController before Prune operation
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: replications
|
||||
- name: Assert DeploymentConfig was deleted
|
||||
assert:
|
||||
that:
|
||||
- _prune is changed
|
||||
- _prune.replication_controllers | length == 1
|
||||
- _prune.replication_controllers.0.details.name == replications.resources.0.metadata.name
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
# Execute Prune without namespace option
|
||||
- name: Read ReplicationController before Prune operation
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ReplicationController
|
||||
namespace: "{{ deployment_ns }}"
|
||||
register: replications
|
||||
|
||||
- name: Prune from all namespace should update more deployments
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
register: _prune
|
||||
- assert:
|
||||
that:
|
||||
- replications.resources | length == 1
|
||||
|
||||
- name: Assure multiple ReplicationController were found for pruning
|
||||
assert:
|
||||
that:
|
||||
- _prune is changed
|
||||
- _prune.replication_controllers | length > 0
|
||||
- name: Prune from all namespace should update more deployments
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
register: _prune
|
||||
|
||||
- name: Assure multiple ReplicationController were found for pruning
|
||||
assert:
|
||||
that:
|
||||
- _prune is changed
|
||||
- _prune.replication_controllers | length > 0
|
||||
|
||||
always:
|
||||
- name: Delete 1st namespace
|
||||
|
||||
@@ -1,240 +1,245 @@
|
||||
---
|
||||
- block:
|
||||
- set_fact:
|
||||
build_ns: "builds"
|
||||
build_config: "start-build"
|
||||
is_name: "ruby"
|
||||
prune_build: "prune-build"
|
||||
- set_fact:
|
||||
build_ns: "builds"
|
||||
build_config: "start-build"
|
||||
is_name: "ruby"
|
||||
prune_build: "prune-build"
|
||||
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: "{{ build_ns }}"
|
||||
- name: Ensure namespace
|
||||
kubernetes.core.k8s:
|
||||
kind: Namespace
|
||||
name: "{{ build_ns }}"
|
||||
|
||||
- name: Create ImageStream
|
||||
community.okd.k8s:
|
||||
namespace: "{{ build_ns }}"
|
||||
definition:
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
metadata:
|
||||
name: "{{ is_name }}"
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: false
|
||||
tags: []
|
||||
- name: Create ImageStream
|
||||
community.okd.k8s:
|
||||
namespace: "{{ build_ns }}"
|
||||
definition:
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
metadata:
|
||||
name: "{{ is_name }}"
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: false
|
||||
tags: []
|
||||
|
||||
- name: Create build configuration
|
||||
community.okd.k8s:
|
||||
namespace: "{{ build_ns }}"
|
||||
definition:
|
||||
kind: BuildConfig
|
||||
apiVersion: build.openshift.io/v1
|
||||
metadata:
|
||||
name: "{{ build_config }}"
|
||||
spec:
|
||||
source:
|
||||
dockerfile: |
|
||||
FROM openshift/ruby-22-centos7
|
||||
RUN sleep 60s
|
||||
USER ansible
|
||||
strategy:
|
||||
type: Docker
|
||||
output:
|
||||
to:
|
||||
kind: "ImageStreamTag"
|
||||
name: "{{ is_name }}:latest"
|
||||
- name: Create build configuration
|
||||
community.okd.k8s:
|
||||
namespace: "{{ build_ns }}"
|
||||
definition:
|
||||
kind: BuildConfig
|
||||
apiVersion: build.openshift.io/v1
|
||||
metadata:
|
||||
name: "{{ build_config }}"
|
||||
spec:
|
||||
source:
|
||||
dockerfile: |
|
||||
FROM openshift/ruby-22-centos7
|
||||
RUN sleep 60s
|
||||
USER ansible
|
||||
strategy:
|
||||
type: Docker
|
||||
output:
|
||||
to:
|
||||
kind: "ImageStreamTag"
|
||||
name: "{{ is_name }}:latest"
|
||||
|
||||
- name: Start Build from Build configuration
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_config_name: "{{ build_config }}"
|
||||
register: new_build
|
||||
- name: Start Build from Build configuration
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_config_name: "{{ build_config }}"
|
||||
register: new_build
|
||||
|
||||
- name: Assert that a build has been created
|
||||
assert:
|
||||
that:
|
||||
- new_build is changed
|
||||
- new_build.builds.0.metadata.name == "{{ build_config }}-1"
|
||||
- name: Assert that a build has been created
|
||||
assert:
|
||||
that:
|
||||
- new_build is changed
|
||||
- new_build.builds.0.metadata.name == "{{ build_config }}-1"
|
||||
|
||||
- name: Start a new Build from previous Build
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_name: "{{ new_build.builds.0.metadata.name }}"
|
||||
register: rerun_build
|
||||
- name: Start a new Build from previous Build
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_name: "{{ new_build.builds.0.metadata.name }}"
|
||||
register: rerun_build
|
||||
|
||||
- name: Assert that another build has been created
|
||||
assert:
|
||||
that:
|
||||
- rerun_build is changed
|
||||
- rerun_build.builds.0.metadata.name == "{{ build_config }}-2"
|
||||
- name: Assert that another build has been created
|
||||
assert:
|
||||
that:
|
||||
- rerun_build is changed
|
||||
- rerun_build.builds.0.metadata.name == "{{ build_config }}-2"
|
||||
|
||||
- name: Cancel first build created
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_name: "{{ build_config }}-1"
|
||||
state: cancelled
|
||||
wait: yes
|
||||
register: cancel
|
||||
- name: Cancel first build created
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_name: "{{ build_config }}-1"
|
||||
state: cancelled
|
||||
wait: yes
|
||||
register: cancel
|
||||
|
||||
- name: Assert that the Build was cancelled
|
||||
assert:
|
||||
that:
|
||||
- cancel is changed
|
||||
- cancel.builds | length == 1
|
||||
- cancel.builds.0.metadata.name == "{{ build_config }}-1"
|
||||
- cancel.builds.0.metadata.namespace == "{{ build_ns }}"
|
||||
- cancel.builds.0.status.cancelled
|
||||
- name: Assert that the Build was cancelled
|
||||
assert:
|
||||
that:
|
||||
- cancel is changed
|
||||
- cancel.builds | length == 1
|
||||
- cancel.builds.0.metadata.name == "{{ build_config }}-1"
|
||||
- cancel.builds.0.metadata.namespace == "{{ build_ns }}"
|
||||
- '"cancelled" in cancel.builds.0.status'
|
||||
- cancel.builds.0.status.cancelled
|
||||
|
||||
- name: Get Build info
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ cancel.builds.0.metadata.name }}"
|
||||
register: build
|
||||
- name: Get info for 1st Build
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ cancel.builds.0.metadata.name }}"
|
||||
register: build
|
||||
|
||||
- name: Assert that build phase is cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- build.resources.0.status.cancelled
|
||||
- build.resources.0.status.phase == 'Cancelled'
|
||||
- name: Assert that build phase is cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- '"cancelled" in build.resources.0.status'
|
||||
- build.resources.0.status.cancelled
|
||||
- build.resources.0.status.phase == 'Cancelled'
|
||||
|
||||
- name: Cancel and restart Build using build config name
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_config_name: "{{ build_config }}"
|
||||
state: restarted
|
||||
build_phases:
|
||||
- Running
|
||||
- New
|
||||
register: restart
|
||||
- name: Cancel and restart Build using build config name
|
||||
community.okd.openshift_build:
|
||||
namespace: "{{ build_ns }}"
|
||||
build_config_name: "{{ build_config }}"
|
||||
state: restarted
|
||||
build_phases:
|
||||
- Pending
|
||||
- Running
|
||||
- New
|
||||
register: restart
|
||||
|
||||
- name: assert that new build was created
|
||||
assert:
|
||||
that:
|
||||
- restart is changed
|
||||
- restart.builds | length == 1
|
||||
- 'restart.builds.0.metadata.name == "{{ build_config }}-3"'
|
||||
|
||||
- name: Get Build 2 info
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ build_config }}-2"
|
||||
register: build
|
||||
- name: assert that new build was created
|
||||
assert:
|
||||
that:
|
||||
- restart is changed
|
||||
- restart.builds | length == 1
|
||||
- 'restart.builds.0.metadata.name == "{{ build_config }}-3"'
|
||||
|
||||
- name: Assert that build phase is cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- build.resources.0.status.cancelled
|
||||
- build.resources.0.status.phase == 'Cancelled'
|
||||
- name: Get info for 2nd Build
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ build_config }}-2"
|
||||
register: build
|
||||
|
||||
- name: Get Build info
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ build_config }}-3"
|
||||
register: build
|
||||
- name: Assert that build phase is cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- '"cancelled" in build.resources.0.status'
|
||||
- build.resources.0.status.cancelled
|
||||
- build.resources.0.status.phase == 'Cancelled'
|
||||
|
||||
- name: Assert that Build is not cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- '"cancelled" not in build.resources.0.status'
|
||||
- "build.resources.0.status.phase in ('New', 'Pending', 'Running')"
|
||||
- name: Get info for 3rd build
|
||||
kubernetes.core.k8s_info:
|
||||
version: build.openshift.io/v1
|
||||
kind: Build
|
||||
namespace: "{{ build_ns }}"
|
||||
name: "{{ build_config }}-3"
|
||||
register: build
|
||||
|
||||
- name: Prune Builds keep younger than 30min
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
keep_younger_than: 30
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune
|
||||
check_mode: yes
|
||||
- name: Assert that Build is not cancelled
|
||||
assert:
|
||||
that:
|
||||
- build.resources | length == 1
|
||||
- '"cancelled" not in build.resources.0.status'
|
||||
- "build.resources.0.status.phase in ('New', 'Pending', 'Running')"
|
||||
|
||||
- name: Assert that no Builds were found
|
||||
assert:
|
||||
that:
|
||||
- not prune.changed
|
||||
- prune.builds | length == 0
|
||||
- name: Prune Builds keep younger than 30min
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
keep_younger_than: 30
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune
|
||||
check_mode: yes
|
||||
|
||||
- name: Prune Builds without namespace
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
register: prune_without_ns
|
||||
check_mode: yes
|
||||
- name: Assert that no Builds were found
|
||||
assert:
|
||||
that:
|
||||
- not prune.changed
|
||||
- prune.builds | length == 0
|
||||
|
||||
- name: Assert that completed build are candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- prune_without_ns is changed
|
||||
- prune_without_ns.builds | length > 0
|
||||
- '"{{ build_config }}-1" in build_names'
|
||||
- '"{{ build_config }}-2" in build_names'
|
||||
vars:
|
||||
build_names: '{{ prune_without_ns.builds | map(attribute="metadata") | flatten | map(attribute="name") | list }}'
|
||||
- name: Prune Builds without namespace
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
register: prune_without_ns
|
||||
check_mode: yes
|
||||
|
||||
- name: Prune Builds using namespace
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune_with_ns
|
||||
check_mode: yes
|
||||
- name: Assert that completed build are candidate for prune
|
||||
assert:
|
||||
that:
|
||||
- prune_without_ns is changed
|
||||
- prune_without_ns.builds | length > 0
|
||||
- '"{{ build_config }}-1" in build_names'
|
||||
- '"{{ build_config }}-2" in build_names'
|
||||
vars:
|
||||
build_names: '{{ prune_without_ns.builds | map(attribute="metadata") | flatten | map(attribute="name") | list }}'
|
||||
|
||||
- name: Assert that prune operation found the completed build
|
||||
assert:
|
||||
that:
|
||||
- prune_with_ns is changed
|
||||
- prune_with_ns.builds | length == 2
|
||||
- name: Prune Builds using namespace
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune_with_ns
|
||||
check_mode: yes
|
||||
|
||||
- name: Check Build before prune
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-1"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
- name: Assert that prune operation found the completed build
|
||||
assert:
|
||||
that:
|
||||
- prune_with_ns is changed
|
||||
- prune_with_ns.builds | length == 2
|
||||
|
||||
- name: Validate that any previous build operation executed with check_mode did not deleted the build
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- name: Check Build before prune
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-1"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
|
||||
- name: Execute prune operation
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune
|
||||
- name: Validate that any previous build operation executed with check_mode did not deleted the build
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
|
||||
- name: assert prune is changed
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
- name: Execute prune operation
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
namespace: "{{ build_ns }}"
|
||||
register: prune
|
||||
|
||||
- name: Check Build
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-1"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
- name: assert prune is changed
|
||||
assert:
|
||||
that:
|
||||
- prune is changed
|
||||
|
||||
- name: Assert that the Build does not exist anymore
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 0
|
||||
- name: Check Build
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-1"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
|
||||
- name: Check Build
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-2"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
- name: Assert that the Build does not exist anymore
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 0
|
||||
|
||||
- name: Assert that the Build does not exist anymore
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 0
|
||||
- name: Check Build
|
||||
kubernetes.core.k8s_info:
|
||||
kind: Build
|
||||
api_version: build.openshift.io/v1
|
||||
name: "{{ build_config }}-2"
|
||||
namespace: "{{ build_ns }}"
|
||||
register: resource
|
||||
|
||||
- name: Assert that the Build does not exist anymore
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 0
|
||||
|
||||
always:
|
||||
- name: Ensure namespace is deleted
|
||||
|
||||
@@ -1,174 +1,175 @@
|
||||
---
|
||||
- name: Openshift import image testing
|
||||
block:
|
||||
|
||||
- set_fact:
|
||||
test_ns: "import-images"
|
||||
- set_fact:
|
||||
test_ns: "import-images"
|
||||
|
||||
- name: Ensure namespace
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ test_ns }}'
|
||||
- name: Ensure namespace
|
||||
community.okd.k8s:
|
||||
kind: Namespace
|
||||
name: '{{ test_ns }}'
|
||||
|
||||
- name: Import image using tag (should import latest tag only)
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
check_mode: yes
|
||||
register: import_tag
|
||||
- name: Import image using tag (should import latest tag only)
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
check_mode: yes
|
||||
register: import_tag
|
||||
|
||||
- name: Assert only latest was imported
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
- import_tag.result | length == 1
|
||||
- import_tag.result.0.spec.import
|
||||
- import_tag.result.0.spec.images.0.from.kind == "DockerImage"
|
||||
- import_tag.result.0.spec.images.0.from.name == "ansible/awx"
|
||||
- name: Assert only latest was imported
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
- import_tag.result | length == 1
|
||||
- import_tag.result.0.spec.import
|
||||
- import_tag.result.0.spec.images.0.from.kind == "DockerImage"
|
||||
- import_tag.result.0.spec.images.0.from.name == "ansible/awx"
|
||||
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: assert that image stream is not created when using check_mode=yes
|
||||
assert:
|
||||
that:
|
||||
- resource.resources == []
|
||||
|
||||
- name: Import image using tag (should import latest tag only)
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
register: import_tag
|
||||
|
||||
- name: Assert only latest was imported
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: assert that image stream contains only tag latest
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags.0.tag == 'latest'
|
||||
|
||||
- name: Import once again the latest tag
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
register: import_tag
|
||||
|
||||
- name: assert change was performed
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
version: image.openshift.io/v1
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: assert that image stream still contains unique tag
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags.0.tag == 'latest'
|
||||
|
||||
- name: Import another tags
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx:17.1.0"
|
||||
register: import_another_tag
|
||||
ignore_errors: yes
|
||||
|
||||
- name: assert that another tag was imported
|
||||
assert:
|
||||
that:
|
||||
- import_another_tag is failed
|
||||
- '"the tag 17.1.0 does not exist on the image stream" in import_another_tag.msg'
|
||||
|
||||
- name: Create simple ImageStream (without docker external container)
|
||||
community.okd.k8s:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "local-is"
|
||||
definition:
|
||||
apiVersion: image.openshift.io/v1
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: false
|
||||
tags: []
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: Import all tag for image stream not pointing on external container image should failed
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "local-is"
|
||||
all: true
|
||||
register: error_tag
|
||||
ignore_errors: true
|
||||
check_mode: yes
|
||||
- name: assert that image stream is not created when using check_mode=yes
|
||||
assert:
|
||||
that:
|
||||
- resource.resources == []
|
||||
|
||||
- name: Assert module cannot import from non-existing tag from ImageStream
|
||||
assert:
|
||||
that:
|
||||
- error_tag is failed
|
||||
- 'error_tag.msg == "image stream {{ test_ns }}/local-is does not have tags pointing to external container images"'
|
||||
- name: Import image using tag (should import latest tag only)
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
register: import_tag
|
||||
|
||||
- name: import all tags for container image ibmcom/pause and specific tag for redhat/ubi8-micro
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name:
|
||||
- "ibmcom/pause"
|
||||
- "redhat/ubi8-micro:8.5-437"
|
||||
all: true
|
||||
register: multiple_import
|
||||
- name: Assert only latest was imported
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
|
||||
- name: Assert that import succeed
|
||||
assert:
|
||||
that:
|
||||
- multiple_import is changed
|
||||
- multiple_import.result | length == 2
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: Read ibmcom/pause ImageStream
|
||||
kubernetes.core.k8s_info:
|
||||
version: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: pause
|
||||
register: pause
|
||||
- name: assert that image stream contains only tag latest
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags.0.tag == 'latest'
|
||||
|
||||
- name: assert that ibmcom/pause has multiple tags
|
||||
assert:
|
||||
that:
|
||||
- pause.resources | length == 1
|
||||
- pause.resources.0.status.tags | length > 1
|
||||
- name: Import once again the latest tag
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx"
|
||||
register: import_tag
|
||||
|
||||
- name: Read redhat/ubi8-micro ImageStream
|
||||
kubernetes.core.k8s_info:
|
||||
version: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: ubi8-micro
|
||||
register: resource
|
||||
- name: assert change was performed
|
||||
assert:
|
||||
that:
|
||||
- import_tag is changed
|
||||
|
||||
- name: assert that redhat/ubi8-micro has only one tag
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags | length == 1
|
||||
- 'resource.resources.0.status.tags.0.tag == "8.5-437"'
|
||||
- name: check image stream
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ImageStream
|
||||
version: image.openshift.io/v1
|
||||
namespace: "{{ test_ns }}"
|
||||
name: awx
|
||||
register: resource
|
||||
|
||||
- name: assert that image stream still contains unique tag
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags.0.tag == 'latest'
|
||||
|
||||
- name: Import another tags
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "ansible/awx:17.1.0"
|
||||
register: import_another_tag
|
||||
ignore_errors: yes
|
||||
|
||||
- name: assert that another tag was imported
|
||||
assert:
|
||||
that:
|
||||
- import_another_tag is failed
|
||||
- '"the tag 17.1.0 does not exist on the image stream" in import_another_tag.msg'
|
||||
|
||||
- name: Create simple ImageStream (without docker external container)
|
||||
community.okd.k8s:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "local-is"
|
||||
definition:
|
||||
apiVersion: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
spec:
|
||||
lookupPolicy:
|
||||
local: false
|
||||
tags: []
|
||||
|
||||
- name: Import all tag for image stream not pointing on external container image should failed
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name: "local-is"
|
||||
all: true
|
||||
register: error_tag
|
||||
ignore_errors: true
|
||||
check_mode: yes
|
||||
|
||||
- name: Assert module cannot import from non-existing tag from ImageStream
|
||||
assert:
|
||||
that:
|
||||
- error_tag is failed
|
||||
- 'error_tag.msg == "image stream {{ test_ns }}/local-is does not have tags pointing to external container images"'
|
||||
|
||||
- name: import all tags for container image ibmcom/pause and specific tag for redhat/ubi8-micro
|
||||
community.okd.openshift_import_image:
|
||||
namespace: "{{ test_ns }}"
|
||||
name:
|
||||
- "ibmcom/pause"
|
||||
- "redhat/ubi8-micro:8.5-437"
|
||||
all: true
|
||||
register: multiple_import
|
||||
|
||||
- name: Assert that import succeed
|
||||
assert:
|
||||
that:
|
||||
- multiple_import is changed
|
||||
- multiple_import.result | length == 2
|
||||
|
||||
- name: Read ibmcom/pause ImageStream
|
||||
kubernetes.core.k8s_info:
|
||||
version: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: pause
|
||||
register: pause
|
||||
|
||||
- name: assert that ibmcom/pause has multiple tags
|
||||
assert:
|
||||
that:
|
||||
- pause.resources | length == 1
|
||||
- pause.resources.0.status.tags | length > 1
|
||||
|
||||
- name: Read redhat/ubi8-micro ImageStream
|
||||
kubernetes.core.k8s_info:
|
||||
version: image.openshift.io/v1
|
||||
kind: ImageStream
|
||||
namespace: "{{ test_ns }}"
|
||||
name: ubi8-micro
|
||||
register: resource
|
||||
|
||||
- name: assert that redhat/ubi8-micro has only one tag
|
||||
assert:
|
||||
that:
|
||||
- resource.resources | length == 1
|
||||
- resource.resources.0.status.tags | length == 1
|
||||
- 'resource.resources.0.status.tags.0.tag == "8.5-437"'
|
||||
|
||||
always:
|
||||
- name: Delete testing namespace
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
name: "{{ pod_name }}"
|
||||
spec:
|
||||
containers:
|
||||
- name: test-container
|
||||
image: "{{ prune_registry }}/{{ prune_ns }}/{{ container.name }}:latest"
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
- name: test-container
|
||||
image: "{{ prune_registry }}/{{ prune_ns }}/{{ container.name }}:latest"
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- while true;do date;sleep 5; done
|
||||
|
||||
- name: Create limit range for images size
|
||||
community.okd.k8s:
|
||||
@@ -57,7 +57,7 @@
|
||||
- type: openshift.io/Image
|
||||
max:
|
||||
storage: 1Gi
|
||||
|
||||
|
||||
- name: Prune images from namespace
|
||||
community.okd.openshift_adm_prune_images:
|
||||
registry_url: "{{ prune_registry }}"
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
app: hello-kubernetes
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-kubernetes
|
||||
image: docker.io/openshift/hello-openshift
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
- name: hello-kubernetes
|
||||
image: docker.io/openshift/hello-openshift
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
|
||||
- name: Create Service
|
||||
community.okd.k8s:
|
||||
@@ -35,8 +35,8 @@
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: hello-kubernetes
|
||||
|
||||
|
||||
@@ -64,14 +64,16 @@ okd_dc_triggers:
|
||||
|
||||
okd_dc_spec:
|
||||
template: '{{ k8s_pod_template }}'
|
||||
triggers: '{{ okd_dc_triggers }}'
|
||||
selector:
|
||||
matchLabels:
|
||||
app: "{{ k8s_pod_name }}"
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
|
||||
okd_dc_template:
|
||||
apiVersion: v1
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec: '{{ okd_dc_spec }}'
|
||||
|
||||
okd_imagestream_template:
|
||||
@@ -83,12 +85,12 @@ okd_imagestream_template:
|
||||
lookupPolicy:
|
||||
local: true
|
||||
tags:
|
||||
- annotations: null
|
||||
from:
|
||||
kind: DockerImage
|
||||
name: '{{ image }}'
|
||||
name: '{{ image_tag }}'
|
||||
referencePolicy:
|
||||
type: Source
|
||||
- annotations: null
|
||||
from:
|
||||
kind: DockerImage
|
||||
name: '{{ image }}'
|
||||
name: '{{ image_tag }}'
|
||||
referencePolicy:
|
||||
type: Source
|
||||
|
||||
image_tag: latest
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
DOCUMENTATION = """
|
||||
author:
|
||||
- xuxinkun (@xuxinkun)
|
||||
|
||||
@@ -145,29 +146,32 @@ DOCUMENTATION = '''
|
||||
env:
|
||||
- name: K8S_AUTH_VERIFY_SSL
|
||||
aliases: [ oc_verify_ssl ]
|
||||
'''
|
||||
"""
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.connection.kubectl import Connection as KubectlConnection
|
||||
from ansible_collections.kubernetes.core.plugins.connection.kubectl import (
|
||||
Connection as KubectlConnection,
|
||||
)
|
||||
|
||||
|
||||
CONNECTION_TRANSPORT = 'oc'
|
||||
CONNECTION_TRANSPORT = "oc"
|
||||
|
||||
CONNECTION_OPTIONS = {
|
||||
'oc_container': '-c',
|
||||
'oc_namespace': '-n',
|
||||
'oc_kubeconfig': '--kubeconfig',
|
||||
'oc_context': '--context',
|
||||
'oc_host': '--server',
|
||||
'client_cert': '--client-certificate',
|
||||
'client_key': '--client-key',
|
||||
'ca_cert': '--certificate-authority',
|
||||
'validate_certs': '--insecure-skip-tls-verify',
|
||||
'oc_token': '--token'
|
||||
"oc_container": "-c",
|
||||
"oc_namespace": "-n",
|
||||
"oc_kubeconfig": "--kubeconfig",
|
||||
"oc_context": "--context",
|
||||
"oc_host": "--server",
|
||||
"client_cert": "--client-certificate",
|
||||
"client_key": "--client-key",
|
||||
"ca_cert": "--certificate-authority",
|
||||
"validate_certs": "--insecure-skip-tls-verify",
|
||||
"oc_token": "--token",
|
||||
}
|
||||
|
||||
|
||||
class Connection(KubectlConnection):
|
||||
''' Local oc based connections '''
|
||||
"""Local oc based connections"""
|
||||
|
||||
transport = CONNECTION_TRANSPORT
|
||||
connection_options = CONNECTION_OPTIONS
|
||||
documentation = DOCUMENTATION
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Copyright (c) 2018 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
DOCUMENTATION = """
|
||||
name: openshift
|
||||
author:
|
||||
- Chris Houseknecht (@chouseknecht)
|
||||
@@ -94,34 +94,41 @@ DOCUMENTATION = '''
|
||||
- "python >= 3.6"
|
||||
- "kubernetes >= 12.0.0"
|
||||
- "PyYAML >= 3.11"
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = '''
|
||||
EXAMPLES = """
|
||||
# File must be named openshift.yaml or openshift.yml
|
||||
|
||||
# Authenticate with token, and return all pods and services for all namespaces
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- host: https://192.168.64.4:8443
|
||||
api_key: xxxxxxxxxxxxxxxx
|
||||
verify_ssl: false
|
||||
- name: Authenticate with token, and return all pods and services for all namespaces
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- host: https://192.168.64.4:8443
|
||||
api_key: xxxxxxxxxxxxxxxx
|
||||
verify_ssl: false
|
||||
|
||||
# Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- namespaces:
|
||||
- testing
|
||||
- name: Use default config (~/.kube/config) file and active context, and return objects for a specific namespace
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- namespaces:
|
||||
- testing
|
||||
|
||||
# Use a custom config file, and a specific context.
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- kubeconfig: /path/to/config
|
||||
context: 'awx/192-168-64-4:8443/developer'
|
||||
'''
|
||||
- name: Use a custom config file, and a specific context.
|
||||
plugin: community.okd.openshift
|
||||
connections:
|
||||
- kubeconfig: /path/to/config
|
||||
context: 'awx/192-168-64-4:8443/developer'
|
||||
"""
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.inventory.k8s import K8sInventoryException, InventoryModule as K8sInventoryModule, format_dynamic_api_exc
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import get_api_client
|
||||
from ansible_collections.kubernetes.core.plugins.inventory.k8s import (
|
||||
K8sInventoryException,
|
||||
InventoryModule as K8sInventoryModule,
|
||||
format_dynamic_api_exc,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import (
|
||||
get_api_client,
|
||||
)
|
||||
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
except ImportError as e:
|
||||
HAS_KUBERNETES_COLLECTION = False
|
||||
@@ -134,22 +141,26 @@ except ImportError:
|
||||
|
||||
|
||||
class InventoryModule(K8sInventoryModule):
|
||||
NAME = 'community.okd.openshift'
|
||||
NAME = "community.okd.openshift"
|
||||
|
||||
connection_plugin = 'community.okd.oc'
|
||||
transport = 'oc'
|
||||
connection_plugin = "community.okd.oc"
|
||||
transport = "oc"
|
||||
|
||||
def check_kubernetes_collection(self):
|
||||
|
||||
if not HAS_KUBERNETES_COLLECTION:
|
||||
K8sInventoryException("The kubernetes.core collection must be installed")
|
||||
raise K8sInventoryException(
|
||||
"The kubernetes.core collection must be installed"
|
||||
)
|
||||
|
||||
def fetch_objects(self, connections):
|
||||
self.check_kubernetes_collection()
|
||||
super(InventoryModule, self).fetch_objects(connections)
|
||||
|
||||
self.display.deprecated("The 'openshift' inventory plugin has been deprecated and will be removed in release 4.0.0",
|
||||
version='4.0.0', collection_name='community.okd')
|
||||
self.display.deprecated(
|
||||
"The 'openshift' inventory plugin has been deprecated and will be removed in release 4.0.0",
|
||||
version="4.0.0",
|
||||
collection_name="community.okd",
|
||||
)
|
||||
|
||||
if connections:
|
||||
if not isinstance(connections, list):
|
||||
@@ -157,9 +168,11 @@ class InventoryModule(K8sInventoryModule):
|
||||
|
||||
for connection in connections:
|
||||
client = get_api_client(**connection)
|
||||
name = connection.get('name', self.get_default_host_name(client.configuration.host))
|
||||
if connection.get('namespaces'):
|
||||
namespaces = connection['namespaces']
|
||||
name = connection.get(
|
||||
"name", self.get_default_host_name(client.configuration.host)
|
||||
)
|
||||
if connection.get("namespaces"):
|
||||
namespaces = connection["namespaces"]
|
||||
else:
|
||||
namespaces = self.get_available_namespaces(client)
|
||||
for namespace in namespaces:
|
||||
@@ -173,15 +186,19 @@ class InventoryModule(K8sInventoryModule):
|
||||
|
||||
def get_routes_for_namespace(self, client, name, namespace):
|
||||
self.check_kubernetes_collection()
|
||||
v1_route = client.resources.get(api_version='route.openshift.io/v1', kind='Route')
|
||||
v1_route = client.resources.get(
|
||||
api_version="route.openshift.io/v1", kind="Route"
|
||||
)
|
||||
try:
|
||||
obj = v1_route.get(namespace=namespace)
|
||||
except DynamicApiError as exc:
|
||||
self.display.debug(exc)
|
||||
raise K8sInventoryException('Error fetching Routes list: %s' % format_dynamic_api_exc(exc))
|
||||
raise K8sInventoryException(
|
||||
"Error fetching Routes list: %s" % format_dynamic_api_exc(exc)
|
||||
)
|
||||
|
||||
namespace_group = 'namespace_{0}'.format(namespace)
|
||||
namespace_routes_group = '{0}_routes'.format(namespace_group)
|
||||
namespace_group = "namespace_{0}".format(namespace)
|
||||
namespace_routes_group = "{0}_routes".format(namespace_group)
|
||||
|
||||
self.inventory.add_group(name)
|
||||
self.inventory.add_group(namespace_group)
|
||||
@@ -190,14 +207,18 @@ class InventoryModule(K8sInventoryModule):
|
||||
self.inventory.add_child(namespace_group, namespace_routes_group)
|
||||
for route in obj.items:
|
||||
route_name = route.metadata.name
|
||||
route_annotations = {} if not route.metadata.annotations else dict(route.metadata.annotations)
|
||||
route_annotations = (
|
||||
{}
|
||||
if not route.metadata.annotations
|
||||
else dict(route.metadata.annotations)
|
||||
)
|
||||
|
||||
self.inventory.add_host(route_name)
|
||||
|
||||
if route.metadata.labels:
|
||||
# create a group for each label_value
|
||||
for key, value in route.metadata.labels:
|
||||
group_name = 'label_{0}_{1}'.format(key, value)
|
||||
group_name = "label_{0}_{1}".format(key, value)
|
||||
self.inventory.add_group(group_name)
|
||||
self.inventory.add_child(group_name, route_name)
|
||||
route_labels = dict(route.metadata.labels)
|
||||
@@ -207,19 +228,25 @@ class InventoryModule(K8sInventoryModule):
|
||||
self.inventory.add_child(namespace_routes_group, route_name)
|
||||
|
||||
# add hostvars
|
||||
self.inventory.set_variable(route_name, 'labels', route_labels)
|
||||
self.inventory.set_variable(route_name, 'annotations', route_annotations)
|
||||
self.inventory.set_variable(route_name, 'cluster_name', route.metadata.clusterName)
|
||||
self.inventory.set_variable(route_name, 'object_type', 'route')
|
||||
self.inventory.set_variable(route_name, 'self_link', route.metadata.selfLink)
|
||||
self.inventory.set_variable(route_name, 'resource_version', route.metadata.resourceVersion)
|
||||
self.inventory.set_variable(route_name, 'uid', route.metadata.uid)
|
||||
self.inventory.set_variable(route_name, "labels", route_labels)
|
||||
self.inventory.set_variable(route_name, "annotations", route_annotations)
|
||||
self.inventory.set_variable(
|
||||
route_name, "cluster_name", route.metadata.clusterName
|
||||
)
|
||||
self.inventory.set_variable(route_name, "object_type", "route")
|
||||
self.inventory.set_variable(
|
||||
route_name, "self_link", route.metadata.selfLink
|
||||
)
|
||||
self.inventory.set_variable(
|
||||
route_name, "resource_version", route.metadata.resourceVersion
|
||||
)
|
||||
self.inventory.set_variable(route_name, "uid", route.metadata.uid)
|
||||
|
||||
if route.spec.host:
|
||||
self.inventory.set_variable(route_name, 'host', route.spec.host)
|
||||
self.inventory.set_variable(route_name, "host", route.spec.host)
|
||||
|
||||
if route.spec.path:
|
||||
self.inventory.set_variable(route_name, 'path', route.spec.path)
|
||||
self.inventory.set_variable(route_name, "path", route.spec.path)
|
||||
|
||||
if hasattr(route.spec.port, 'targetPort') and route.spec.port.targetPort:
|
||||
self.inventory.set_variable(route_name, 'port', dict(route.spec.port))
|
||||
if hasattr(route.spec.port, "targetPort") and route.spec.port.targetPort:
|
||||
self.inventory.set_variable(route_name, "port", dict(route.spec.port))
|
||||
|
||||
@@ -1,35 +1,46 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
import operator
|
||||
from functools import reduce
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.resource import create_definitions
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import CoreException
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.resource import (
|
||||
create_definitions,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import (
|
||||
CoreException,
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError, NotFoundError, ForbiddenError
|
||||
from kubernetes.dynamic.exceptions import (
|
||||
DynamicApiError,
|
||||
NotFoundError,
|
||||
ForbiddenError,
|
||||
)
|
||||
except ImportError as e:
|
||||
pass
|
||||
|
||||
|
||||
TRIGGER_ANNOTATION = 'image.openshift.io/triggers'
|
||||
TRIGGER_CONTAINER = re.compile(r"(?P<path>.*)\[((?P<index>[0-9]+)|\?\(@\.name==[\"'\\]*(?P<name>[a-z0-9]([-a-z0-9]*[a-z0-9])?))")
|
||||
TRIGGER_ANNOTATION = "image.openshift.io/triggers"
|
||||
TRIGGER_CONTAINER = re.compile(
|
||||
r"(?P<path>.*)\[((?P<index>[0-9]+)|\?\(@\.name==[\"'\\]*(?P<name>[a-z0-9]([-a-z0-9]*[a-z0-9])?))"
|
||||
)
|
||||
|
||||
|
||||
class OKDRawModule(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super(OKDRawModule, self).__init__(**kwargs)
|
||||
|
||||
@property
|
||||
@@ -50,36 +61,60 @@ class OKDRawModule(AnsibleOpenshiftModule):
|
||||
result = {"changed": False, "result": {}}
|
||||
warnings = []
|
||||
|
||||
if self.params.get("state") != 'absent':
|
||||
if self.params.get("state") != "absent":
|
||||
existing = None
|
||||
name = definition.get("metadata", {}).get("name")
|
||||
namespace = definition.get("metadata", {}).get("namespace")
|
||||
if definition.get("kind") in ['Project', 'ProjectRequest']:
|
||||
if definition.get("kind") in ["Project", "ProjectRequest"]:
|
||||
try:
|
||||
resource = self.svc.find_resource(kind=definition.get("kind"), api_version=definition.get("apiVersion", "v1"))
|
||||
existing = resource.get(name=name, namespace=namespace).to_dict()
|
||||
resource = self.svc.find_resource(
|
||||
kind=definition.get("kind"),
|
||||
api_version=definition.get("apiVersion", "v1"),
|
||||
)
|
||||
existing = resource.get(
|
||||
name=name, namespace=namespace
|
||||
).to_dict()
|
||||
except (NotFoundError, ForbiddenError):
|
||||
result = self.create_project_request(definition)
|
||||
changed |= result["changed"]
|
||||
results.append(result)
|
||||
continue
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg='Failed to retrieve requested object: {0}'.format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
self.fail_json(
|
||||
msg="Failed to retrieve requested object: {0}".format(
|
||||
exc.body
|
||||
),
|
||||
error=exc.status,
|
||||
status=exc.status,
|
||||
reason=exc.reason,
|
||||
)
|
||||
|
||||
if definition.get("kind") not in ['Project', 'ProjectRequest']:
|
||||
if definition.get("kind") not in ["Project", "ProjectRequest"]:
|
||||
try:
|
||||
resource = self.svc.find_resource(kind=definition.get("kind"), api_version=definition.get("apiVersion", "v1"))
|
||||
existing = resource.get(name=name, namespace=namespace).to_dict()
|
||||
resource = self.svc.find_resource(
|
||||
kind=definition.get("kind"),
|
||||
api_version=definition.get("apiVersion", "v1"),
|
||||
)
|
||||
existing = resource.get(
|
||||
name=name, namespace=namespace
|
||||
).to_dict()
|
||||
except Exception:
|
||||
existing = None
|
||||
|
||||
if existing:
|
||||
if resource.kind == 'DeploymentConfig':
|
||||
if definition.get('spec', {}).get('triggers'):
|
||||
definition = self.resolve_imagestream_triggers(existing, definition)
|
||||
elif existing['metadata'].get('annotations', {}).get(TRIGGER_ANNOTATION):
|
||||
definition = self.resolve_imagestream_trigger_annotation(existing, definition)
|
||||
if resource.kind == "DeploymentConfig":
|
||||
if definition.get("spec", {}).get("triggers"):
|
||||
definition = self.resolve_imagestream_triggers(
|
||||
existing, definition
|
||||
)
|
||||
elif (
|
||||
existing["metadata"]
|
||||
.get("annotations", {})
|
||||
.get(TRIGGER_ANNOTATION)
|
||||
):
|
||||
definition = self.resolve_imagestream_trigger_annotation(
|
||||
existing, definition
|
||||
)
|
||||
|
||||
if self.params.get("validate") is not None:
|
||||
warnings = self.validate(definition)
|
||||
@@ -116,13 +151,15 @@ class OKDRawModule(AnsibleOpenshiftModule):
|
||||
|
||||
@staticmethod
|
||||
def get_index(desired, objects, keys):
|
||||
""" Iterates over keys, returns the first object from objects where the value of the key
|
||||
matches the value in desired
|
||||
"""Iterates over keys, returns the first object from objects where the value of the key
|
||||
matches the value in desired
|
||||
"""
|
||||
# pylint: disable=use-a-generator
|
||||
# Use a generator instead 'all(desired.get(key, True) == item.get(key, False) for key in keys)'
|
||||
for i, item in enumerate(objects):
|
||||
if item and all([desired.get(key, True) == item.get(key, False) for key in keys]):
|
||||
if item and all(
|
||||
[desired.get(key, True) == item.get(key, False) for key in keys]
|
||||
):
|
||||
return i
|
||||
|
||||
def resolve_imagestream_trigger_annotation(self, existing, definition):
|
||||
@@ -137,84 +174,148 @@ class OKDRawModule(AnsibleOpenshiftModule):
|
||||
def set_from_fields(d, fields, value):
|
||||
get_from_fields(d, fields[:-1])[fields[-1]] = value
|
||||
|
||||
if TRIGGER_ANNOTATION in definition['metadata'].get('annotations', {}).keys():
|
||||
triggers = yaml.safe_load(definition['metadata']['annotations'][TRIGGER_ANNOTATION] or '[]')
|
||||
if TRIGGER_ANNOTATION in definition["metadata"].get("annotations", {}).keys():
|
||||
triggers = yaml.safe_load(
|
||||
definition["metadata"]["annotations"][TRIGGER_ANNOTATION] or "[]"
|
||||
)
|
||||
else:
|
||||
triggers = yaml.safe_load(existing['metadata'].get('annotations', '{}').get(TRIGGER_ANNOTATION, '[]'))
|
||||
triggers = yaml.safe_load(
|
||||
existing["metadata"]
|
||||
.get("annotations", "{}")
|
||||
.get(TRIGGER_ANNOTATION, "[]")
|
||||
)
|
||||
|
||||
if not isinstance(triggers, list):
|
||||
return definition
|
||||
|
||||
for trigger in triggers:
|
||||
if trigger.get('fieldPath'):
|
||||
parsed = self.parse_trigger_fieldpath(trigger['fieldPath'])
|
||||
path = parsed.get('path', '').split('.')
|
||||
if trigger.get("fieldPath"):
|
||||
parsed = self.parse_trigger_fieldpath(trigger["fieldPath"])
|
||||
path = parsed.get("path", "").split(".")
|
||||
if path:
|
||||
existing_containers = get_from_fields(existing, path)
|
||||
new_containers = get_from_fields(definition, path)
|
||||
if parsed.get('name'):
|
||||
existing_index = self.get_index({'name': parsed['name']}, existing_containers, ['name'])
|
||||
new_index = self.get_index({'name': parsed['name']}, new_containers, ['name'])
|
||||
elif parsed.get('index') is not None:
|
||||
existing_index = new_index = int(parsed['index'])
|
||||
if parsed.get("name"):
|
||||
existing_index = self.get_index(
|
||||
{"name": parsed["name"]}, existing_containers, ["name"]
|
||||
)
|
||||
new_index = self.get_index(
|
||||
{"name": parsed["name"]}, new_containers, ["name"]
|
||||
)
|
||||
elif parsed.get("index") is not None:
|
||||
existing_index = new_index = int(parsed["index"])
|
||||
else:
|
||||
existing_index = new_index = None
|
||||
if existing_index is not None and new_index is not None:
|
||||
if existing_index < len(existing_containers) and new_index < len(new_containers):
|
||||
set_from_fields(definition, path + [new_index, 'image'], get_from_fields(existing, path + [existing_index, 'image']))
|
||||
if existing_index < len(
|
||||
existing_containers
|
||||
) and new_index < len(new_containers):
|
||||
set_from_fields(
|
||||
definition,
|
||||
path + [new_index, "image"],
|
||||
get_from_fields(
|
||||
existing, path + [existing_index, "image"]
|
||||
),
|
||||
)
|
||||
return definition
|
||||
|
||||
def resolve_imagestream_triggers(self, existing, definition):
|
||||
|
||||
existing_triggers = existing.get('spec', {}).get('triggers')
|
||||
new_triggers = definition['spec']['triggers']
|
||||
existing_containers = existing.get('spec', {}).get('template', {}).get('spec', {}).get('containers', [])
|
||||
new_containers = definition.get('spec', {}).get('template', {}).get('spec', {}).get('containers', [])
|
||||
existing_triggers = existing.get("spec", {}).get("triggers")
|
||||
new_triggers = definition["spec"]["triggers"]
|
||||
existing_containers = (
|
||||
existing.get("spec", {})
|
||||
.get("template", {})
|
||||
.get("spec", {})
|
||||
.get("containers", [])
|
||||
)
|
||||
new_containers = (
|
||||
definition.get("spec", {})
|
||||
.get("template", {})
|
||||
.get("spec", {})
|
||||
.get("containers", [])
|
||||
)
|
||||
for i, trigger in enumerate(new_triggers):
|
||||
if trigger.get('type') == 'ImageChange' and trigger.get('imageChangeParams'):
|
||||
names = trigger['imageChangeParams'].get('containerNames', [])
|
||||
if trigger.get("type") == "ImageChange" and trigger.get(
|
||||
"imageChangeParams"
|
||||
):
|
||||
names = trigger["imageChangeParams"].get("containerNames", [])
|
||||
for name in names:
|
||||
old_container_index = self.get_index({'name': name}, existing_containers, ['name'])
|
||||
new_container_index = self.get_index({'name': name}, new_containers, ['name'])
|
||||
if old_container_index is not None and new_container_index is not None:
|
||||
image = existing['spec']['template']['spec']['containers'][old_container_index]['image']
|
||||
definition['spec']['template']['spec']['containers'][new_container_index]['image'] = image
|
||||
old_container_index = self.get_index(
|
||||
{"name": name}, existing_containers, ["name"]
|
||||
)
|
||||
new_container_index = self.get_index(
|
||||
{"name": name}, new_containers, ["name"]
|
||||
)
|
||||
if (
|
||||
old_container_index is not None
|
||||
and new_container_index is not None
|
||||
):
|
||||
image = existing["spec"]["template"]["spec"]["containers"][
|
||||
old_container_index
|
||||
]["image"]
|
||||
definition["spec"]["template"]["spec"]["containers"][
|
||||
new_container_index
|
||||
]["image"] = image
|
||||
|
||||
existing_index = self.get_index(trigger['imageChangeParams'],
|
||||
[x.get('imageChangeParams') for x in existing_triggers],
|
||||
['containerNames'])
|
||||
existing_index = self.get_index(
|
||||
trigger["imageChangeParams"],
|
||||
[x.get("imageChangeParams") for x in existing_triggers],
|
||||
["containerNames"],
|
||||
)
|
||||
if existing_index is not None:
|
||||
existing_image = existing_triggers[existing_index].get('imageChangeParams', {}).get('lastTriggeredImage')
|
||||
existing_image = (
|
||||
existing_triggers[existing_index]
|
||||
.get("imageChangeParams", {})
|
||||
.get("lastTriggeredImage")
|
||||
)
|
||||
if existing_image:
|
||||
definition['spec']['triggers'][i]['imageChangeParams']['lastTriggeredImage'] = existing_image
|
||||
existing_from = existing_triggers[existing_index].get('imageChangeParams', {}).get('from', {})
|
||||
new_from = trigger['imageChangeParams'].get('from', {})
|
||||
existing_namespace = existing_from.get('namespace')
|
||||
existing_name = existing_from.get('name', False)
|
||||
new_name = new_from.get('name', True)
|
||||
add_namespace = existing_namespace and 'namespace' not in new_from.keys() and existing_name == new_name
|
||||
definition["spec"]["triggers"][i]["imageChangeParams"][
|
||||
"lastTriggeredImage"
|
||||
] = existing_image
|
||||
existing_from = (
|
||||
existing_triggers[existing_index]
|
||||
.get("imageChangeParams", {})
|
||||
.get("from", {})
|
||||
)
|
||||
new_from = trigger["imageChangeParams"].get("from", {})
|
||||
existing_namespace = existing_from.get("namespace")
|
||||
existing_name = existing_from.get("name", False)
|
||||
new_name = new_from.get("name", True)
|
||||
add_namespace = (
|
||||
existing_namespace
|
||||
and "namespace" not in new_from.keys()
|
||||
and existing_name == new_name
|
||||
)
|
||||
if add_namespace:
|
||||
definition['spec']['triggers'][i]['imageChangeParams']['from']['namespace'] = existing_from['namespace']
|
||||
definition["spec"]["triggers"][i]["imageChangeParams"][
|
||||
"from"
|
||||
]["namespace"] = existing_from["namespace"]
|
||||
|
||||
return definition
|
||||
|
||||
def parse_trigger_fieldpath(self, expression):
|
||||
parsed = TRIGGER_CONTAINER.search(expression).groupdict()
|
||||
if parsed.get('index'):
|
||||
parsed['index'] = int(parsed['index'])
|
||||
if parsed.get("index"):
|
||||
parsed["index"] = int(parsed["index"])
|
||||
return parsed
|
||||
|
||||
def create_project_request(self, definition):
|
||||
definition['kind'] = 'ProjectRequest'
|
||||
result = {'changed': False, 'result': {}}
|
||||
resource = self.svc.find_resource(kind='ProjectRequest', api_version=definition['apiVersion'], fail=True)
|
||||
definition["kind"] = "ProjectRequest"
|
||||
result = {"changed": False, "result": {}}
|
||||
resource = self.svc.find_resource(
|
||||
kind="ProjectRequest", api_version=definition["apiVersion"], fail=True
|
||||
)
|
||||
if not self.check_mode:
|
||||
try:
|
||||
k8s_obj = resource.create(definition)
|
||||
result['result'] = k8s_obj.to_dict()
|
||||
result["result"] = k8s_obj.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg="Failed to create object: {0}".format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
result['changed'] = True
|
||||
result['method'] = 'create'
|
||||
self.fail_json(
|
||||
msg="Failed to create object: {0}".format(exc.body),
|
||||
error=exc.status,
|
||||
status=exc.status,
|
||||
reason=exc.reason,
|
||||
)
|
||||
result["changed"] = True
|
||||
result["method"] = "create"
|
||||
return result
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes import client
|
||||
@@ -18,31 +21,36 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftAdmPruneAuth, self).__init__(**kwargs)
|
||||
|
||||
def prune_resource_binding(self, kind, api_version, ref_kind, ref_namespace_names, propagation_policy=None):
|
||||
|
||||
def prune_resource_binding(
|
||||
self, kind, api_version, ref_kind, ref_namespace_names, propagation_policy=None
|
||||
):
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
candidates = []
|
||||
for ref_namespace, ref_name in ref_namespace_names:
|
||||
try:
|
||||
result = resource.get(name=None, namespace=ref_namespace)
|
||||
result = result.to_dict()
|
||||
result = result.get('items') if 'items' in result else [result]
|
||||
result = result.get("items") if "items" in result else [result]
|
||||
for obj in result:
|
||||
namespace = obj['metadata'].get('namespace', None)
|
||||
name = obj['metadata'].get('name')
|
||||
if ref_kind and obj['roleRef']['kind'] != ref_kind:
|
||||
namespace = obj["metadata"].get("namespace", None)
|
||||
name = obj["metadata"].get("name")
|
||||
if ref_kind and obj["roleRef"]["kind"] != ref_kind:
|
||||
# skip this binding as the roleRef.kind does not match
|
||||
continue
|
||||
if obj['roleRef']['name'] == ref_name:
|
||||
if obj["roleRef"]["name"] == ref_name:
|
||||
# select this binding as the roleRef.name match
|
||||
candidates.append((namespace, name))
|
||||
except NotFoundError:
|
||||
continue
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to get {kind} resource due to: {msg}".format(kind=kind, msg=exc.body)
|
||||
msg = "Failed to get {kind} resource due to: {msg}".format(
|
||||
kind=kind, msg=exc.body
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
except Exception as e:
|
||||
msg = "Failed to get {kind} due to: {msg}".format(kind=kind, msg=to_native(e))
|
||||
msg = "Failed to get {kind} due to: {msg}".format(
|
||||
kind=kind, msg=to_native(e)
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
|
||||
if len(candidates) == 0 or self.check_mode:
|
||||
@@ -54,24 +62,29 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
|
||||
for namespace, name in candidates:
|
||||
try:
|
||||
result = resource.delete(name=name, namespace=namespace, body=delete_options)
|
||||
result = resource.delete(
|
||||
name=name, namespace=namespace, body=delete_options
|
||||
)
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete {kind} {namespace}/{name} due to: {msg}".format(kind=kind, namespace=namespace, name=name, msg=exc.body)
|
||||
msg = "Failed to delete {kind} {namespace}/{name} due to: {msg}".format(
|
||||
kind=kind, namespace=namespace, name=name, msg=exc.body
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete {kind} {namespace}/{name} due to: {msg}".format(kind=kind, namespace=namespace, name=name, msg=to_native(e))
|
||||
msg = "Failed to delete {kind} {namespace}/{name} due to: {msg}".format(
|
||||
kind=kind, namespace=namespace, name=name, msg=to_native(e)
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
return [y if x is None else x + "/" + y for x, y in candidates]
|
||||
|
||||
def update_resource_binding(self, ref_kind, ref_names, namespaced=False):
|
||||
|
||||
kind = 'ClusterRoleBinding'
|
||||
api_version = "rbac.authorization.k8s.io/v1",
|
||||
kind = "ClusterRoleBinding"
|
||||
api_version = "rbac.authorization.k8s.io/v1"
|
||||
if namespaced:
|
||||
kind = "RoleBinding"
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
result = resource.get(name=None, namespace=None).to_dict()
|
||||
result = result.get('items') if 'items' in result else [result]
|
||||
result = result.get("items") if "items" in result else [result]
|
||||
|
||||
if len(result) == 0:
|
||||
return [], False
|
||||
@@ -79,29 +92,40 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
def _update_user_group(binding_namespace, subjects):
|
||||
users, groups = [], []
|
||||
for x in subjects:
|
||||
if x['kind'] == 'User':
|
||||
users.append(x['name'])
|
||||
elif x['kind'] == 'Group':
|
||||
groups.append(x['name'])
|
||||
elif x['kind'] == 'ServiceAccount':
|
||||
if x["kind"] == "User":
|
||||
users.append(x["name"])
|
||||
elif x["kind"] == "Group":
|
||||
groups.append(x["name"])
|
||||
elif x["kind"] == "ServiceAccount":
|
||||
namespace = binding_namespace
|
||||
if x.get('namespace') is not None:
|
||||
namespace = x.get('namespace')
|
||||
if x.get("namespace") is not None:
|
||||
namespace = x.get("namespace")
|
||||
if namespace is not None:
|
||||
users.append("system:serviceaccount:%s:%s" % (namespace, x['name']))
|
||||
users.append(
|
||||
"system:serviceaccount:%s:%s" % (namespace, x["name"])
|
||||
)
|
||||
return users, groups
|
||||
|
||||
candidates = []
|
||||
changed = False
|
||||
for item in result:
|
||||
subjects = item.get('subjects', [])
|
||||
retainedSubjects = [x for x in subjects if x['kind'] == ref_kind and x['name'] in ref_names]
|
||||
subjects = item.get("subjects", [])
|
||||
retainedSubjects = [
|
||||
x for x in subjects if x["kind"] == ref_kind and x["name"] in ref_names
|
||||
]
|
||||
if len(subjects) != len(retainedSubjects):
|
||||
updated_binding = item
|
||||
updated_binding['subjects'] = retainedSubjects
|
||||
binding_namespace = item['metadata'].get('namespace', None)
|
||||
updated_binding['userNames'], updated_binding['groupNames'] = _update_user_group(binding_namespace, retainedSubjects)
|
||||
candidates.append(binding_namespace + "/" + item['metadata']['name'] if binding_namespace else item['metadata']['name'])
|
||||
updated_binding["subjects"] = retainedSubjects
|
||||
binding_namespace = item["metadata"].get("namespace", None)
|
||||
(
|
||||
updated_binding["userNames"],
|
||||
updated_binding["groupNames"],
|
||||
) = _update_user_group(binding_namespace, retainedSubjects)
|
||||
candidates.append(
|
||||
binding_namespace + "/" + item["metadata"]["name"]
|
||||
if binding_namespace
|
||||
else item["metadata"]["name"]
|
||||
)
|
||||
changed = True
|
||||
if not self.check_mode:
|
||||
try:
|
||||
@@ -112,20 +136,25 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
return candidates, changed
|
||||
|
||||
def update_security_context(self, ref_names, key):
|
||||
params = {'kind': 'SecurityContextConstraints', 'api_version': 'security.openshift.io/v1'}
|
||||
params = {
|
||||
"kind": "SecurityContextConstraints",
|
||||
"api_version": "security.openshift.io/v1",
|
||||
}
|
||||
sccs = self.kubernetes_facts(**params)
|
||||
if not sccs['api_found']:
|
||||
self.fail_json(msg=sccs['msg'])
|
||||
sccs = sccs.get('resources')
|
||||
if not sccs["api_found"]:
|
||||
self.fail_json(msg=sccs["msg"])
|
||||
sccs = sccs.get("resources")
|
||||
|
||||
candidates = []
|
||||
changed = False
|
||||
resource = self.find_resource(kind="SecurityContextConstraints", api_version="security.openshift.io/v1")
|
||||
resource = self.find_resource(
|
||||
kind="SecurityContextConstraints", api_version="security.openshift.io/v1"
|
||||
)
|
||||
for item in sccs:
|
||||
subjects = item.get(key, [])
|
||||
retainedSubjects = [x for x in subjects if x not in ref_names]
|
||||
if len(subjects) != len(retainedSubjects):
|
||||
candidates.append(item['metadata']['name'])
|
||||
candidates.append(item["metadata"]["name"])
|
||||
changed = True
|
||||
if not self.check_mode:
|
||||
upd_sec_ctx = item
|
||||
@@ -138,94 +167,116 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
return candidates, changed
|
||||
|
||||
def auth_prune_roles(self):
|
||||
params = {'kind': 'Role', 'api_version': 'rbac.authorization.k8s.io/v1', 'namespace': self.params.get('namespace')}
|
||||
for attr in ('name', 'label_selectors'):
|
||||
params = {
|
||||
"kind": "Role",
|
||||
"api_version": "rbac.authorization.k8s.io/v1",
|
||||
"namespace": self.params.get("namespace"),
|
||||
}
|
||||
for attr in ("name", "label_selectors"):
|
||||
if self.params.get(attr):
|
||||
params[attr] = self.params.get(attr)
|
||||
|
||||
result = self.kubernetes_facts(**params)
|
||||
if not result['api_found']:
|
||||
self.fail_json(msg=result['msg'])
|
||||
if not result["api_found"]:
|
||||
self.fail_json(msg=result["msg"])
|
||||
|
||||
roles = result.get('resources')
|
||||
roles = result.get("resources")
|
||||
if len(roles) == 0:
|
||||
self.exit_json(changed=False, msg="No candidate rolebinding to prune from namespace %s." % self.params.get('namespace'))
|
||||
self.exit_json(
|
||||
changed=False,
|
||||
msg="No candidate rolebinding to prune from namespace %s."
|
||||
% self.params.get("namespace"),
|
||||
)
|
||||
|
||||
ref_roles = [(x['metadata']['namespace'], x['metadata']['name']) for x in roles]
|
||||
candidates = self.prune_resource_binding(kind="RoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind="Role",
|
||||
ref_namespace_names=ref_roles,
|
||||
propagation_policy='Foreground')
|
||||
ref_roles = [(x["metadata"]["namespace"], x["metadata"]["name"]) for x in roles]
|
||||
candidates = self.prune_resource_binding(
|
||||
kind="RoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind="Role",
|
||||
ref_namespace_names=ref_roles,
|
||||
propagation_policy="Foreground",
|
||||
)
|
||||
if len(candidates) == 0:
|
||||
self.exit_json(changed=False, role_binding=candidates)
|
||||
|
||||
self.exit_json(changed=True, role_binding=candidates)
|
||||
|
||||
def auth_prune_clusterroles(self):
|
||||
params = {'kind': 'ClusterRole', 'api_version': 'rbac.authorization.k8s.io/v1'}
|
||||
for attr in ('name', 'label_selectors'):
|
||||
params = {"kind": "ClusterRole", "api_version": "rbac.authorization.k8s.io/v1"}
|
||||
for attr in ("name", "label_selectors"):
|
||||
if self.params.get(attr):
|
||||
params[attr] = self.params.get(attr)
|
||||
|
||||
result = self.kubernetes_facts(**params)
|
||||
if not result['api_found']:
|
||||
self.fail_json(msg=result['msg'])
|
||||
if not result["api_found"]:
|
||||
self.fail_json(msg=result["msg"])
|
||||
|
||||
clusterroles = result.get('resources')
|
||||
clusterroles = result.get("resources")
|
||||
if len(clusterroles) == 0:
|
||||
self.exit_json(changed=False, msg="No clusterroles found matching input criteria.")
|
||||
self.exit_json(
|
||||
changed=False, msg="No clusterroles found matching input criteria."
|
||||
)
|
||||
|
||||
ref_clusterroles = [(None, x['metadata']['name']) for x in clusterroles]
|
||||
ref_clusterroles = [(None, x["metadata"]["name"]) for x in clusterroles]
|
||||
|
||||
# Prune ClusterRoleBinding
|
||||
candidates_cluster_binding = self.prune_resource_binding(kind="ClusterRoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind=None,
|
||||
ref_namespace_names=ref_clusterroles)
|
||||
candidates_cluster_binding = self.prune_resource_binding(
|
||||
kind="ClusterRoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind=None,
|
||||
ref_namespace_names=ref_clusterroles,
|
||||
)
|
||||
|
||||
# Prune Role Binding
|
||||
candidates_namespaced_binding = self.prune_resource_binding(kind="RoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind='ClusterRole',
|
||||
ref_namespace_names=ref_clusterroles)
|
||||
candidates_namespaced_binding = self.prune_resource_binding(
|
||||
kind="RoleBinding",
|
||||
api_version="rbac.authorization.k8s.io/v1",
|
||||
ref_kind="ClusterRole",
|
||||
ref_namespace_names=ref_clusterroles,
|
||||
)
|
||||
|
||||
self.exit_json(changed=True,
|
||||
cluster_role_binding=candidates_cluster_binding,
|
||||
role_binding=candidates_namespaced_binding)
|
||||
self.exit_json(
|
||||
changed=True,
|
||||
cluster_role_binding=candidates_cluster_binding,
|
||||
role_binding=candidates_namespaced_binding,
|
||||
)
|
||||
|
||||
def list_groups(self, params=None):
|
||||
options = {'kind': 'Group', 'api_version': 'user.openshift.io/v1'}
|
||||
options = {"kind": "Group", "api_version": "user.openshift.io/v1"}
|
||||
if params:
|
||||
for attr in ('name', 'label_selectors'):
|
||||
for attr in ("name", "label_selectors"):
|
||||
if params.get(attr):
|
||||
options[attr] = params.get(attr)
|
||||
return self.kubernetes_facts(**options)
|
||||
|
||||
def auth_prune_users(self):
|
||||
params = {'kind': 'User', 'api_version': 'user.openshift.io/v1'}
|
||||
for attr in ('name', 'label_selectors'):
|
||||
params = {"kind": "User", "api_version": "user.openshift.io/v1"}
|
||||
for attr in ("name", "label_selectors"):
|
||||
if self.params.get(attr):
|
||||
params[attr] = self.params.get(attr)
|
||||
|
||||
users = self.kubernetes_facts(**params)
|
||||
if len(users) == 0:
|
||||
self.exit_json(changed=False, msg="No resource type 'User' found matching input criteria.")
|
||||
self.exit_json(
|
||||
changed=False,
|
||||
msg="No resource type 'User' found matching input criteria.",
|
||||
)
|
||||
|
||||
names = [x['metadata']['name'] for x in users]
|
||||
names = [x["metadata"]["name"] for x in users]
|
||||
changed = False
|
||||
# Remove the user role binding
|
||||
rolebinding, changed_role = self.update_resource_binding(ref_kind="User",
|
||||
ref_names=names,
|
||||
namespaced=True)
|
||||
rolebinding, changed_role = self.update_resource_binding(
|
||||
ref_kind="User", ref_names=names, namespaced=True
|
||||
)
|
||||
changed = changed or changed_role
|
||||
# Remove the user cluster role binding
|
||||
clusterrolesbinding, changed_cr = self.update_resource_binding(ref_kind="User",
|
||||
ref_names=names)
|
||||
clusterrolesbinding, changed_cr = self.update_resource_binding(
|
||||
ref_kind="User", ref_names=names
|
||||
)
|
||||
changed = changed or changed_cr
|
||||
|
||||
# Remove the user from security context constraints
|
||||
sccs, changed_sccs = self.update_security_context(names, 'users')
|
||||
sccs, changed_sccs = self.update_security_context(names, "users")
|
||||
changed = changed or changed_sccs
|
||||
|
||||
# Remove the user from groups
|
||||
@@ -233,14 +284,14 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
deleted_groups = []
|
||||
resource = self.find_resource(kind="Group", api_version="user.openshift.io/v1")
|
||||
for grp in groups:
|
||||
subjects = grp.get('users', [])
|
||||
subjects = grp.get("users", [])
|
||||
retainedSubjects = [x for x in subjects if x not in names]
|
||||
if len(subjects) != len(retainedSubjects):
|
||||
deleted_groups.append(grp['metadata']['name'])
|
||||
deleted_groups.append(grp["metadata"]["name"])
|
||||
changed = True
|
||||
if not self.check_mode:
|
||||
upd_group = grp
|
||||
upd_group.update({'users': retainedSubjects})
|
||||
upd_group.update({"users": retainedSubjects})
|
||||
try:
|
||||
resource.apply(upd_group, namespace=None)
|
||||
except DynamicApiError as exc:
|
||||
@@ -248,62 +299,82 @@ class OpenShiftAdmPruneAuth(AnsibleOpenshiftModule):
|
||||
self.fail_json(msg=msg)
|
||||
|
||||
# Remove the user's OAuthClientAuthorizations
|
||||
oauth = self.kubernetes_facts(kind='OAuthClientAuthorization', api_version='oauth.openshift.io/v1')
|
||||
oauth = self.kubernetes_facts(
|
||||
kind="OAuthClientAuthorization", api_version="oauth.openshift.io/v1"
|
||||
)
|
||||
deleted_auths = []
|
||||
resource = self.find_resource(kind="OAuthClientAuthorization", api_version="oauth.openshift.io/v1")
|
||||
resource = self.find_resource(
|
||||
kind="OAuthClientAuthorization", api_version="oauth.openshift.io/v1"
|
||||
)
|
||||
for authorization in oauth:
|
||||
if authorization.get('userName', None) in names:
|
||||
auth_name = authorization['metadata']['name']
|
||||
if authorization.get("userName", None) in names:
|
||||
auth_name = authorization["metadata"]["name"]
|
||||
deleted_auths.append(auth_name)
|
||||
changed = True
|
||||
if not self.check_mode:
|
||||
try:
|
||||
resource.delete(name=auth_name, namespace=None, body=client.V1DeleteOptions())
|
||||
resource.delete(
|
||||
name=auth_name,
|
||||
namespace=None,
|
||||
body=client.V1DeleteOptions(),
|
||||
)
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete OAuthClientAuthorization {name} due to: {msg}".format(name=auth_name, msg=exc.body)
|
||||
msg = "Failed to delete OAuthClientAuthorization {name} due to: {msg}".format(
|
||||
name=auth_name, msg=exc.body
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete OAuthClientAuthorization {name} due to: {msg}".format(name=auth_name, msg=to_native(e))
|
||||
msg = "Failed to delete OAuthClientAuthorization {name} due to: {msg}".format(
|
||||
name=auth_name, msg=to_native(e)
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
|
||||
self.exit_json(changed=changed,
|
||||
cluster_role_binding=clusterrolesbinding,
|
||||
role_binding=rolebinding,
|
||||
security_context_constraints=sccs,
|
||||
authorization=deleted_auths,
|
||||
group=deleted_groups)
|
||||
self.exit_json(
|
||||
changed=changed,
|
||||
cluster_role_binding=clusterrolesbinding,
|
||||
role_binding=rolebinding,
|
||||
security_context_constraints=sccs,
|
||||
authorization=deleted_auths,
|
||||
group=deleted_groups,
|
||||
)
|
||||
|
||||
def auth_prune_groups(self):
|
||||
groups = self.list_groups(params=self.params)
|
||||
if len(groups) == 0:
|
||||
self.exit_json(changed=False, result="No resource type 'Group' found matching input criteria.")
|
||||
self.exit_json(
|
||||
changed=False,
|
||||
result="No resource type 'Group' found matching input criteria.",
|
||||
)
|
||||
|
||||
names = [x['metadata']['name'] for x in groups]
|
||||
names = [x["metadata"]["name"] for x in groups]
|
||||
|
||||
changed = False
|
||||
# Remove the groups role binding
|
||||
rolebinding, changed_role = self.update_resource_binding(ref_kind="Group",
|
||||
ref_names=names,
|
||||
namespaced=True)
|
||||
rolebinding, changed_role = self.update_resource_binding(
|
||||
ref_kind="Group", ref_names=names, namespaced=True
|
||||
)
|
||||
changed = changed or changed_role
|
||||
# Remove the groups cluster role binding
|
||||
clusterrolesbinding, changed_cr = self.update_resource_binding(ref_kind="Group",
|
||||
ref_names=names)
|
||||
clusterrolesbinding, changed_cr = self.update_resource_binding(
|
||||
ref_kind="Group", ref_names=names
|
||||
)
|
||||
changed = changed or changed_cr
|
||||
# Remove the groups security context constraints
|
||||
sccs, changed_sccs = self.update_security_context(names, 'groups')
|
||||
sccs, changed_sccs = self.update_security_context(names, "groups")
|
||||
changed = changed or changed_sccs
|
||||
|
||||
self.exit_json(changed=changed,
|
||||
cluster_role_binding=clusterrolesbinding,
|
||||
role_binding=rolebinding,
|
||||
security_context_constraints=sccs)
|
||||
self.exit_json(
|
||||
changed=changed,
|
||||
cluster_role_binding=clusterrolesbinding,
|
||||
role_binding=rolebinding,
|
||||
security_context_constraints=sccs,
|
||||
)
|
||||
|
||||
def execute_module(self):
|
||||
auth_prune = {
|
||||
'roles': self.auth_prune_roles,
|
||||
'clusterroles': self.auth_prune_clusterroles,
|
||||
'users': self.auth_prune_users,
|
||||
'groups': self.auth_prune_groups,
|
||||
"roles": self.auth_prune_roles,
|
||||
"clusterroles": self.auth_prune_clusterroles,
|
||||
"users": self.auth_prune_users,
|
||||
"groups": self.auth_prune_groups,
|
||||
}
|
||||
auth_prune[self.params.get('resource')]()
|
||||
auth_prune[self.params.get("resource")]()
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from datetime import datetime, timezone
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes import client
|
||||
@@ -23,7 +25,9 @@ def get_deploymentconfig_for_replicationcontroller(replica_controller):
|
||||
# This is set on replication controller pod template by deployer controller.
|
||||
DeploymentConfigAnnotation = "openshift.io/deployment-config.name"
|
||||
try:
|
||||
deploymentconfig_name = replica_controller['metadata']['annotations'].get(DeploymentConfigAnnotation)
|
||||
deploymentconfig_name = replica_controller["metadata"]["annotations"].get(
|
||||
DeploymentConfigAnnotation
|
||||
)
|
||||
if deploymentconfig_name is None or deploymentconfig_name == "":
|
||||
return None
|
||||
return deploymentconfig_name
|
||||
@@ -32,7 +36,6 @@ def get_deploymentconfig_for_replicationcontroller(replica_controller):
|
||||
|
||||
|
||||
class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(OpenShiftAdmPruneDeployment, self).__init__(**kwargs)
|
||||
|
||||
@@ -41,27 +44,33 @@ class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
return get_deploymentconfig_for_replicationcontroller(obj) is not None
|
||||
|
||||
def _zeroReplicaSize(obj):
|
||||
return obj['spec']['replicas'] == 0 and obj['status']['replicas'] == 0
|
||||
return obj["spec"]["replicas"] == 0 and obj["status"]["replicas"] == 0
|
||||
|
||||
def _complete_failed(obj):
|
||||
DeploymentStatusAnnotation = "openshift.io/deployment.phase"
|
||||
try:
|
||||
# validate that replication controller status is either 'Complete' or 'Failed'
|
||||
deployment_phase = obj['metadata']['annotations'].get(DeploymentStatusAnnotation)
|
||||
return deployment_phase in ('Failed', 'Complete')
|
||||
deployment_phase = obj["metadata"]["annotations"].get(
|
||||
DeploymentStatusAnnotation
|
||||
)
|
||||
return deployment_phase in ("Failed", "Complete")
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _younger(obj):
|
||||
creation_timestamp = datetime.strptime(obj['metadata']['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ')
|
||||
creation_timestamp = datetime.strptime(
|
||||
obj["metadata"]["creationTimestamp"], "%Y-%m-%dT%H:%M:%SZ"
|
||||
)
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
age = (now - creation_timestamp).seconds / 60
|
||||
return age > self.params['keep_younger_than']
|
||||
return age > self.params["keep_younger_than"]
|
||||
|
||||
def _orphan(obj):
|
||||
try:
|
||||
# verify if the deploymentconfig associated to the replication controller is still existing
|
||||
deploymentconfig_name = get_deploymentconfig_for_replicationcontroller(obj)
|
||||
deploymentconfig_name = get_deploymentconfig_for_replicationcontroller(
|
||||
obj
|
||||
)
|
||||
params = dict(
|
||||
kind="DeploymentConfig",
|
||||
api_version="apps.openshift.io/v1",
|
||||
@@ -69,14 +78,14 @@ class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
namespace=obj["metadata"]["name"],
|
||||
)
|
||||
exists = self.kubernetes_facts(**params)
|
||||
return not (exists.get['api_found'] and len(exists['resources']) > 0)
|
||||
return not (exists.get["api_found"] and len(exists["resources"]) > 0)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
predicates = [_deployment, _zeroReplicaSize, _complete_failed]
|
||||
if self.params['orphans']:
|
||||
if self.params["orphans"]:
|
||||
predicates.append(_orphan)
|
||||
if self.params['keep_younger_than']:
|
||||
if self.params["keep_younger_than"]:
|
||||
predicates.append(_younger)
|
||||
|
||||
results = replicacontrollers.copy()
|
||||
@@ -86,8 +95,8 @@ class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
|
||||
def execute_module(self):
|
||||
# list replicationcontroller candidate for pruning
|
||||
kind = 'ReplicationController'
|
||||
api_version = 'v1'
|
||||
kind = "ReplicationController"
|
||||
api_version = "v1"
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
|
||||
# Get ReplicationController
|
||||
@@ -103,7 +112,7 @@ class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
self.exit_json(changed=False, replication_controllers=[])
|
||||
|
||||
changed = True
|
||||
delete_options = client.V1DeleteOptions(propagation_policy='Background')
|
||||
delete_options = client.V1DeleteOptions(propagation_policy="Background")
|
||||
replication_controllers = []
|
||||
for replica in candidates:
|
||||
try:
|
||||
@@ -111,12 +120,18 @@ class OpenShiftAdmPruneDeployment(AnsibleOpenshiftModule):
|
||||
if not self.check_mode:
|
||||
name = replica["metadata"]["name"]
|
||||
namespace = replica["metadata"]["namespace"]
|
||||
result = resource.delete(name=name, namespace=namespace, body=delete_options).to_dict()
|
||||
result = resource.delete(
|
||||
name=name, namespace=namespace, body=delete_options
|
||||
).to_dict()
|
||||
replication_controllers.append(result)
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete ReplicationController {namespace}/{name} due to: {msg}".format(namespace=namespace, name=name, msg=exc.body)
|
||||
msg = "Failed to delete ReplicationController {namespace}/{name} due to: {msg}".format(
|
||||
namespace=namespace, name=name, msg=exc.body
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete ReplicationController {namespace}/{name} due to: {msg}".format(namespace=namespace, name=name, msg=to_native(e))
|
||||
msg = "Failed to delete ReplicationController {namespace}/{name} due to: {msg}".format(
|
||||
namespace=namespace, name=name, msg=to_native(e)
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
self.exit_json(changed=changed, replication_controllers=replication_controllers)
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from datetime import datetime, timezone, timedelta
|
||||
import traceback
|
||||
import copy
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_images_common import (
|
||||
OpenShiftAnalyzeImageStream,
|
||||
@@ -30,7 +32,7 @@ try:
|
||||
from kubernetes.dynamic.exceptions import (
|
||||
DynamicApiError,
|
||||
NotFoundError,
|
||||
ApiException
|
||||
ApiException,
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -67,18 +69,20 @@ def determine_host_registry(module, images, image_streams):
|
||||
managed_images = list(filter(_f_managed_images, images))
|
||||
|
||||
# Be sure to pick up the newest managed image which should have an up to date information
|
||||
sorted_images = sorted(managed_images,
|
||||
key=lambda x: x["metadata"]["creationTimestamp"],
|
||||
reverse=True)
|
||||
sorted_images = sorted(
|
||||
managed_images, key=lambda x: x["metadata"]["creationTimestamp"], reverse=True
|
||||
)
|
||||
docker_image_ref = ""
|
||||
if len(sorted_images) > 0:
|
||||
docker_image_ref = sorted_images[0].get("dockerImageReference", "")
|
||||
else:
|
||||
# 2nd try to get the pull spec from any image stream
|
||||
# Sorting by creation timestamp may not get us up to date info. Modification time would be much
|
||||
sorted_image_streams = sorted(image_streams,
|
||||
key=lambda x: x["metadata"]["creationTimestamp"],
|
||||
reverse=True)
|
||||
sorted_image_streams = sorted(
|
||||
image_streams,
|
||||
key=lambda x: x["metadata"]["creationTimestamp"],
|
||||
reverse=True,
|
||||
)
|
||||
for i_stream in sorted_image_streams:
|
||||
docker_image_ref = i_stream["status"].get("dockerImageRepository", "")
|
||||
if len(docker_image_ref) > 0:
|
||||
@@ -88,7 +92,7 @@ def determine_host_registry(module, images, image_streams):
|
||||
module.exit_json(changed=False, result="no managed image found")
|
||||
|
||||
result, error = parse_docker_image_ref(docker_image_ref, module)
|
||||
return result['hostname']
|
||||
return result["hostname"]
|
||||
|
||||
|
||||
class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
@@ -97,7 +101,7 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
|
||||
self.max_creation_timestamp = self.get_max_creation_timestamp()
|
||||
self._rest_client = None
|
||||
self.registryhost = self.params.get('registry_url')
|
||||
self.registryhost = self.params.get("registry_url")
|
||||
self.changed = False
|
||||
|
||||
def list_objects(self):
|
||||
@@ -107,9 +111,9 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
if self.params.get("namespace") and kind.lower() == "imagestream":
|
||||
namespace = self.params.get("namespace")
|
||||
try:
|
||||
result[kind] = self.kubernetes_facts(kind=kind,
|
||||
api_version=version,
|
||||
namespace=namespace).get('resources')
|
||||
result[kind] = self.kubernetes_facts(
|
||||
kind=kind, api_version=version, namespace=namespace
|
||||
).get("resources")
|
||||
except DynamicApiError as e:
|
||||
self.fail_json(
|
||||
msg="An error occurred while trying to list objects.",
|
||||
@@ -119,7 +123,7 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
except Exception as e:
|
||||
self.fail_json(
|
||||
msg="An error occurred while trying to list objects.",
|
||||
error=to_native(e)
|
||||
error=to_native(e),
|
||||
)
|
||||
return result
|
||||
|
||||
@@ -134,8 +138,8 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
def rest_client(self):
|
||||
if not self._rest_client:
|
||||
configuration = copy.deepcopy(self.client.configuration)
|
||||
validate_certs = self.params.get('registry_validate_certs')
|
||||
ssl_ca_cert = self.params.get('registry_ca_cert')
|
||||
validate_certs = self.params.get("registry_validate_certs")
|
||||
ssl_ca_cert = self.params.get("registry_ca_cert")
|
||||
if validate_certs is not None:
|
||||
configuration.verify_ssl = validate_certs
|
||||
if ssl_ca_cert is not None:
|
||||
@@ -146,7 +150,9 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
|
||||
def delete_from_registry(self, url):
|
||||
try:
|
||||
response = self.rest_client.DELETE(url=url, headers=self.client.configuration.api_key)
|
||||
response = self.rest_client.DELETE(
|
||||
url=url, headers=self.client.configuration.api_key
|
||||
)
|
||||
if response.status == 404:
|
||||
# Unable to delete layer
|
||||
return None
|
||||
@@ -156,8 +162,9 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
if response.status != 202 and response.status != 204:
|
||||
self.fail_json(
|
||||
msg="Delete URL {0}: Unexpected status code in response: {1}".format(
|
||||
response.status, url),
|
||||
reason=response.reason
|
||||
response.status, url
|
||||
),
|
||||
reason=response.reason,
|
||||
)
|
||||
return None
|
||||
except ApiException as e:
|
||||
@@ -204,9 +211,7 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
result = self.request(
|
||||
"PUT",
|
||||
"/apis/{api_version}/namespaces/{namespace}/imagestreams/{name}/status".format(
|
||||
api_version=api_version,
|
||||
namespace=namespace,
|
||||
name=name
|
||||
api_version=api_version, namespace=namespace, name=name
|
||||
),
|
||||
body=definition,
|
||||
content_type="application/json",
|
||||
@@ -237,11 +242,10 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
pass
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(
|
||||
msg="Failed to delete object %s/%s due to: %s" % (
|
||||
kind, name, exc.body
|
||||
),
|
||||
msg="Failed to delete object %s/%s due to: %s"
|
||||
% (kind, name, exc.body),
|
||||
reason=exc.reason,
|
||||
status=exc.status
|
||||
status=exc.status,
|
||||
)
|
||||
else:
|
||||
existing = resource.get(name=name)
|
||||
@@ -285,9 +289,11 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
continue
|
||||
|
||||
if idx == 0:
|
||||
istag = "%s/%s:%s" % (stream_namespace,
|
||||
stream_name,
|
||||
tag_event_list["tag"])
|
||||
istag = "%s/%s:%s" % (
|
||||
stream_namespace,
|
||||
stream_name,
|
||||
tag_event_list["tag"],
|
||||
)
|
||||
if istag in self.used_tags:
|
||||
# keeping because tag is used
|
||||
filtered_items.append(item)
|
||||
@@ -302,20 +308,20 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
|
||||
image = self.image_mapping[item["image"]]
|
||||
# check prune over limit size
|
||||
if prune_over_size_limit and not self.exceeds_limits(stream_namespace, image):
|
||||
if prune_over_size_limit and not self.exceeds_limits(
|
||||
stream_namespace, image
|
||||
):
|
||||
filtered_items.append(item)
|
||||
continue
|
||||
|
||||
image_ref = "%s/%s@%s" % (stream_namespace,
|
||||
stream_name,
|
||||
item["image"])
|
||||
image_ref = "%s/%s@%s" % (stream_namespace, stream_name, item["image"])
|
||||
if image_ref in self.used_images:
|
||||
# keeping because tag is used
|
||||
filtered_items.append(item)
|
||||
continue
|
||||
|
||||
images_to_delete.append(item["image"])
|
||||
if self.params.get('prune_registry'):
|
||||
if self.params.get("prune_registry"):
|
||||
manifests_to_delete.append(image["metadata"]["name"])
|
||||
path = stream_namespace + "/" + stream_name
|
||||
image_blobs, err = get_image_blobs(image)
|
||||
@@ -325,21 +331,25 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
return filtered_items, manifests_to_delete, images_to_delete
|
||||
|
||||
def prune_image_streams(self, stream):
|
||||
name = stream['metadata']['namespace'] + "/" + stream['metadata']['name']
|
||||
name = stream["metadata"]["namespace"] + "/" + stream["metadata"]["name"]
|
||||
if is_too_young_object(stream, self.max_creation_timestamp):
|
||||
# keeping all images because of image stream too young
|
||||
return None, []
|
||||
facts = self.kubernetes_facts(kind="ImageStream",
|
||||
api_version=ApiConfiguration.get("ImageStream"),
|
||||
name=stream["metadata"]["name"],
|
||||
namespace=stream["metadata"]["namespace"])
|
||||
image_stream = facts.get('resources')
|
||||
facts = self.kubernetes_facts(
|
||||
kind="ImageStream",
|
||||
api_version=ApiConfiguration.get("ImageStream"),
|
||||
name=stream["metadata"]["name"],
|
||||
namespace=stream["metadata"]["namespace"],
|
||||
)
|
||||
image_stream = facts.get("resources")
|
||||
if len(image_stream) != 1:
|
||||
# skipping because it does not exist anymore
|
||||
return None, []
|
||||
stream = image_stream[0]
|
||||
namespace = self.params.get("namespace")
|
||||
stream_to_update = not namespace or (stream["metadata"]["namespace"] == namespace)
|
||||
stream_to_update = not namespace or (
|
||||
stream["metadata"]["namespace"] == namespace
|
||||
)
|
||||
|
||||
manifests_to_delete, images_to_delete = [], []
|
||||
deleted_items = False
|
||||
@@ -351,9 +361,9 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
(
|
||||
filtered_tag_event,
|
||||
tag_manifests_to_delete,
|
||||
tag_images_to_delete
|
||||
tag_images_to_delete,
|
||||
) = self.prune_image_stream_tag(stream, tag_event_list)
|
||||
stream['status']['tags'][idx]['items'] = filtered_tag_event
|
||||
stream["status"]["tags"][idx]["items"] = filtered_tag_event
|
||||
manifests_to_delete += tag_manifests_to_delete
|
||||
images_to_delete += tag_images_to_delete
|
||||
deleted_items = deleted_items or (len(tag_images_to_delete) > 0)
|
||||
@@ -361,11 +371,11 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
# Deleting tags without items
|
||||
tags = []
|
||||
for tag in stream["status"].get("tags", []):
|
||||
if tag['items'] is None or len(tag['items']) == 0:
|
||||
if tag["items"] is None or len(tag["items"]) == 0:
|
||||
continue
|
||||
tags.append(tag)
|
||||
|
||||
stream['status']['tags'] = tags
|
||||
stream["status"]["tags"] = tags
|
||||
result = None
|
||||
# Update ImageStream
|
||||
if stream_to_update:
|
||||
@@ -402,19 +412,23 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
|
||||
def execute_module(self):
|
||||
resources = self.list_objects()
|
||||
if not self.check_mode and self.params.get('prune_registry'):
|
||||
if not self.check_mode and self.params.get("prune_registry"):
|
||||
if not self.registryhost:
|
||||
self.registryhost = determine_host_registry(self.module, resources['Image'], resources['ImageStream'])
|
||||
self.registryhost = determine_host_registry(
|
||||
self.module, resources["Image"], resources["ImageStream"]
|
||||
)
|
||||
# validate that host has a scheme
|
||||
if "://" not in self.registryhost:
|
||||
self.registryhost = "https://" + self.registryhost
|
||||
# Analyze Image Streams
|
||||
analyze_ref = OpenShiftAnalyzeImageStream(
|
||||
ignore_invalid_refs=self.params.get('ignore_invalid_refs'),
|
||||
ignore_invalid_refs=self.params.get("ignore_invalid_refs"),
|
||||
max_creation_timestamp=self.max_creation_timestamp,
|
||||
module=self.module
|
||||
module=self.module,
|
||||
)
|
||||
self.used_tags, self.used_images, error = analyze_ref.analyze_image_stream(
|
||||
resources
|
||||
)
|
||||
self.used_tags, self.used_images, error = analyze_ref.analyze_image_stream(resources)
|
||||
if error:
|
||||
self.fail_json(msg=error)
|
||||
|
||||
@@ -435,16 +449,20 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
updated_image_streams = []
|
||||
deleted_tags_images = []
|
||||
updated_is_mapping = {}
|
||||
for stream in resources['ImageStream']:
|
||||
for stream in resources["ImageStream"]:
|
||||
result, images_to_delete = self.prune_image_streams(stream)
|
||||
if result:
|
||||
updated_is_mapping[result["metadata"]["namespace"] + "/" + result["metadata"]["name"]] = result
|
||||
updated_is_mapping[
|
||||
result["metadata"]["namespace"] + "/" + result["metadata"]["name"]
|
||||
] = result
|
||||
updated_image_streams.append(result)
|
||||
deleted_tags_images += images_to_delete
|
||||
|
||||
# Create a list with images referenced on image stream
|
||||
self.referenced_images = []
|
||||
for item in self.kubernetes_facts(kind="ImageStream", api_version="image.openshift.io/v1")["resources"]:
|
||||
for item in self.kubernetes_facts(
|
||||
kind="ImageStream", api_version="image.openshift.io/v1"
|
||||
)["resources"]:
|
||||
name = "%s/%s" % (item["metadata"]["namespace"], item["metadata"]["name"])
|
||||
if name in updated_is_mapping:
|
||||
item = updated_is_mapping[name]
|
||||
@@ -453,7 +471,7 @@ class OpenShiftAdmPruneImages(AnsibleOpenshiftModule):
|
||||
|
||||
# Stage 2: delete images
|
||||
images = []
|
||||
images_to_delete = [x["metadata"]["name"] for x in resources['Image']]
|
||||
images_to_delete = [x["metadata"]["name"] for x in resources["Image"]]
|
||||
if self.params.get("namespace") is not None:
|
||||
# When namespace is defined, prune only images that were referenced by ImageStream
|
||||
# from the corresponding namespace
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from datetime import datetime, timezone, timedelta
|
||||
import traceback
|
||||
import time
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -36,8 +38,7 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
result = self.request(
|
||||
method="POST",
|
||||
path="/apis/build.openshift.io/v1/namespaces/{namespace}/builds/{name}/clone".format(
|
||||
namespace=namespace,
|
||||
name=name
|
||||
namespace=namespace, name=name
|
||||
),
|
||||
body=request,
|
||||
content_type="application/json",
|
||||
@@ -47,7 +48,11 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
msg = "Failed to clone Build %s/%s due to: %s" % (namespace, name, exc.body)
|
||||
self.fail_json(msg=msg, status=exc.status, reason=exc.reason)
|
||||
except Exception as e:
|
||||
msg = "Failed to clone Build %s/%s due to: %s" % (namespace, name, to_native(e))
|
||||
msg = "Failed to clone Build %s/%s due to: %s" % (
|
||||
namespace,
|
||||
name,
|
||||
to_native(e),
|
||||
)
|
||||
self.fail_json(msg=msg, error=to_native(e), exception=e)
|
||||
|
||||
def instantiate_build_config(self, name, namespace, request):
|
||||
@@ -55,22 +60,28 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
result = self.request(
|
||||
method="POST",
|
||||
path="/apis/build.openshift.io/v1/namespaces/{namespace}/buildconfigs/{name}/instantiate".format(
|
||||
namespace=namespace,
|
||||
name=name
|
||||
namespace=namespace, name=name
|
||||
),
|
||||
body=request,
|
||||
content_type="application/json",
|
||||
)
|
||||
return result.to_dict()
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to instantiate BuildConfig %s/%s due to: %s" % (namespace, name, exc.body)
|
||||
msg = "Failed to instantiate BuildConfig %s/%s due to: %s" % (
|
||||
namespace,
|
||||
name,
|
||||
exc.body,
|
||||
)
|
||||
self.fail_json(msg=msg, status=exc.status, reason=exc.reason)
|
||||
except Exception as e:
|
||||
msg = "Failed to instantiate BuildConfig %s/%s due to: %s" % (namespace, name, to_native(e))
|
||||
msg = "Failed to instantiate BuildConfig %s/%s due to: %s" % (
|
||||
namespace,
|
||||
name,
|
||||
to_native(e),
|
||||
)
|
||||
self.fail_json(msg=msg, error=to_native(e), exception=e)
|
||||
|
||||
def start_build(self):
|
||||
|
||||
result = None
|
||||
name = self.params.get("build_config_name")
|
||||
if not name:
|
||||
@@ -79,32 +90,20 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
build_request = {
|
||||
"kind": "BuildRequest",
|
||||
"apiVersion": "build.openshift.io/v1",
|
||||
"metadata": {
|
||||
"name": name
|
||||
},
|
||||
"triggeredBy": [
|
||||
{"message": "Manually triggered"}
|
||||
],
|
||||
"metadata": {"name": name},
|
||||
"triggeredBy": [{"message": "Manually triggered"}],
|
||||
}
|
||||
|
||||
# Overrides incremental
|
||||
incremental = self.params.get("incremental")
|
||||
if incremental is not None:
|
||||
build_request.update(
|
||||
{
|
||||
"sourceStrategyOptions": {
|
||||
"incremental": incremental
|
||||
}
|
||||
}
|
||||
{"sourceStrategyOptions": {"incremental": incremental}}
|
||||
)
|
||||
|
||||
# Environment variable
|
||||
if self.params.get("env_vars"):
|
||||
build_request.update(
|
||||
{
|
||||
"env": self.params.get("env_vars")
|
||||
}
|
||||
)
|
||||
build_request.update({"env": self.params.get("env_vars")})
|
||||
|
||||
# Docker strategy option
|
||||
if self.params.get("build_args"):
|
||||
@@ -121,22 +120,14 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
if no_cache is not None:
|
||||
build_request.update(
|
||||
{
|
||||
"dockerStrategyOptions": {
|
||||
"noCache": no_cache
|
||||
},
|
||||
"dockerStrategyOptions": {"noCache": no_cache},
|
||||
}
|
||||
)
|
||||
|
||||
# commit
|
||||
if self.params.get("commit"):
|
||||
build_request.update(
|
||||
{
|
||||
"revision": {
|
||||
"git": {
|
||||
"commit": self.params.get("commit")
|
||||
}
|
||||
}
|
||||
}
|
||||
{"revision": {"git": {"commit": self.params.get("commit")}}}
|
||||
)
|
||||
|
||||
if self.params.get("build_config_name"):
|
||||
@@ -144,7 +135,7 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
result = self.instantiate_build_config(
|
||||
name=self.params.get("build_config_name"),
|
||||
namespace=self.params.get("namespace"),
|
||||
request=build_request
|
||||
request=build_request,
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -152,7 +143,7 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
result = self.clone_build(
|
||||
name=self.params.get("build_name"),
|
||||
namespace=self.params.get("namespace"),
|
||||
request=build_request
|
||||
request=build_request,
|
||||
)
|
||||
|
||||
if result and self.params.get("wait"):
|
||||
@@ -179,10 +170,11 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
break
|
||||
elif last_status_phase in ("Cancelled", "Error", "Failed"):
|
||||
self.fail_json(
|
||||
msg="Unexpected status for Build %s/%s: %s" % (
|
||||
msg="Unexpected status for Build %s/%s: %s"
|
||||
% (
|
||||
result["metadata"]["name"],
|
||||
result["metadata"]["namespace"],
|
||||
last_status_phase
|
||||
last_status_phase,
|
||||
)
|
||||
)
|
||||
time.sleep(wait_sleep)
|
||||
@@ -190,8 +182,11 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
if last_status_phase != "Complete":
|
||||
name = result["metadata"]["name"]
|
||||
namespace = result["metadata"]["namespace"]
|
||||
msg = "Build %s/%s has not complete after %d second(s)," \
|
||||
"current status is %s" % (namespace, name, wait_timeout, last_status_phase)
|
||||
msg = (
|
||||
"Build %s/%s has not complete after %d second(s),"
|
||||
"current status is %s"
|
||||
% (namespace, name, wait_timeout, last_status_phase)
|
||||
)
|
||||
|
||||
self.fail_json(msg=msg)
|
||||
|
||||
@@ -199,9 +194,8 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
self.exit_json(changed=True, builds=result)
|
||||
|
||||
def cancel_build(self, restart):
|
||||
|
||||
kind = 'Build'
|
||||
api_version = 'build.openshift.io/v1'
|
||||
kind = "Build"
|
||||
api_version = "build.openshift.io/v1"
|
||||
|
||||
namespace = self.params.get("namespace")
|
||||
phases = ["new", "pending", "running"]
|
||||
@@ -215,16 +209,18 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
else:
|
||||
build_config = self.params.get("build_config_name")
|
||||
# list all builds from namespace
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
namespace=namespace
|
||||
)
|
||||
params = dict(kind=kind, api_version=api_version, namespace=namespace)
|
||||
resources = self.kubernetes_facts(**params).get("resources", [])
|
||||
|
||||
def _filter_builds(build):
|
||||
config = build["metadata"].get("labels", {}).get("openshift.io/build-config.name")
|
||||
return build_config is None or (build_config is not None and config in build_config)
|
||||
config = (
|
||||
build["metadata"]
|
||||
.get("labels", {})
|
||||
.get("openshift.io/build-config.name")
|
||||
)
|
||||
return build_config is None or (
|
||||
build_config is not None and config in build_config
|
||||
)
|
||||
|
||||
for item in list(filter(_filter_builds, resources)):
|
||||
name = item["metadata"]["name"]
|
||||
@@ -232,16 +228,15 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
names.append(name)
|
||||
|
||||
if len(names) == 0:
|
||||
self.exit_json(changed=False, msg="No Build found from namespace %s" % namespace)
|
||||
self.exit_json(
|
||||
changed=False, msg="No Build found from namespace %s" % namespace
|
||||
)
|
||||
|
||||
warning = []
|
||||
builds_to_cancel = []
|
||||
for name in names:
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
name=name,
|
||||
namespace=namespace
|
||||
kind=kind, api_version=api_version, name=name, namespace=namespace
|
||||
)
|
||||
|
||||
resource = self.kubernetes_facts(**params).get("resources", [])
|
||||
@@ -256,7 +251,10 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
if phase in phases:
|
||||
builds_to_cancel.append(resource)
|
||||
else:
|
||||
warning.append("build %s/%s is not in expected phase, found %s" % (namespace, name, phase))
|
||||
warning.append(
|
||||
"build %s/%s is not in expected phase, found %s"
|
||||
% (namespace, name, phase)
|
||||
)
|
||||
|
||||
changed = False
|
||||
result = []
|
||||
@@ -278,9 +276,10 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
result.append(cancelled_build)
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(
|
||||
msg="Failed to cancel Build %s/%s due to: %s" % (namespace, name, exc),
|
||||
msg="Failed to cancel Build %s/%s due to: %s"
|
||||
% (namespace, name, exc),
|
||||
reason=exc.reason,
|
||||
status=exc.status
|
||||
status=exc.status,
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail_json(
|
||||
@@ -294,10 +293,7 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
name = build["metadata"]["name"]
|
||||
while (datetime.now() - start).seconds < wait_timeout:
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
name=name,
|
||||
namespace=namespace
|
||||
kind=kind, api_version=api_version, name=name, namespace=namespace
|
||||
)
|
||||
resource = self.kubernetes_facts(**params).get("resources", [])
|
||||
if len(resource) == 0:
|
||||
@@ -307,7 +303,11 @@ class OpenShiftBuilds(AnsibleOpenshiftModule):
|
||||
if last_phase == "Cancelled":
|
||||
return resource, None
|
||||
time.sleep(wait_sleep)
|
||||
return None, "Build %s/%s is not cancelled as expected, current state is %s" % (namespace, name, last_phase)
|
||||
return (
|
||||
None,
|
||||
"Build %s/%s is not cancelled as expected, current state is %s"
|
||||
% (namespace, name, last_phase),
|
||||
)
|
||||
|
||||
if result and self.params.get("wait"):
|
||||
wait_timeout = self.params.get("wait_timeout")
|
||||
@@ -341,8 +341,8 @@ class OpenShiftPruneBuilds(OpenShiftBuilds):
|
||||
|
||||
def execute_module(self):
|
||||
# list replicationcontroller candidate for pruning
|
||||
kind = 'Build'
|
||||
api_version = 'build.openshift.io/v1'
|
||||
kind = "Build"
|
||||
api_version = "build.openshift.io/v1"
|
||||
resource = self.find_resource(kind=kind, api_version=api_version, fail=True)
|
||||
|
||||
self.max_creation_timestamp = None
|
||||
@@ -352,7 +352,12 @@ class OpenShiftPruneBuilds(OpenShiftBuilds):
|
||||
self.max_creation_timestamp = now - timedelta(minutes=keep_younger_than)
|
||||
|
||||
def _prunable_build(build):
|
||||
return build["status"]["phase"] in ("Complete", "Failed", "Error", "Cancelled")
|
||||
return build["status"]["phase"] in (
|
||||
"Complete",
|
||||
"Failed",
|
||||
"Error",
|
||||
"Cancelled",
|
||||
)
|
||||
|
||||
def _orphan_build(build):
|
||||
if not _prunable_build(build):
|
||||
@@ -367,7 +372,9 @@ class OpenShiftPruneBuilds(OpenShiftBuilds):
|
||||
def _younger_build(build):
|
||||
if not self.max_creation_timestamp:
|
||||
return False
|
||||
creation_timestamp = datetime.strptime(build['metadata']['creationTimestamp'], '%Y-%m-%dT%H:%M:%SZ')
|
||||
creation_timestamp = datetime.strptime(
|
||||
build["metadata"]["creationTimestamp"], "%Y-%m-%dT%H:%M:%SZ"
|
||||
)
|
||||
return creation_timestamp < self.max_creation_timestamp
|
||||
|
||||
predicates = [
|
||||
@@ -401,9 +408,17 @@ class OpenShiftPruneBuilds(OpenShiftBuilds):
|
||||
namespace = build["metadata"]["namespace"]
|
||||
resource.delete(name=name, namespace=namespace, body={})
|
||||
except DynamicApiError as exc:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, exc.body)
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (
|
||||
namespace,
|
||||
name,
|
||||
exc.body,
|
||||
)
|
||||
self.fail_json(msg=msg, status=exc.status, reason=exc.reason)
|
||||
except Exception as e:
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (namespace, name, to_native(e))
|
||||
msg = "Failed to delete Build %s/%s due to: %s" % (
|
||||
namespace,
|
||||
name,
|
||||
to_native(e),
|
||||
)
|
||||
self.fail_json(msg=msg, error=to_native(e), exception=e)
|
||||
self.exit_json(changed=changed, builds=candidates)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
@@ -9,8 +10,12 @@ from abc import abstractmethod
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import get_api_client
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import AnsibleK8SModule
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import (
|
||||
get_api_client,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import (
|
||||
AnsibleK8SModule,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import (
|
||||
K8sService,
|
||||
diff_objects,
|
||||
@@ -24,7 +29,10 @@ try:
|
||||
merge_params,
|
||||
flatten_list_kind,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import CoreException
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import (
|
||||
CoreException,
|
||||
)
|
||||
|
||||
HAS_KUBERNETES_COLLECTION = True
|
||||
k8s_collection_import_exception = None
|
||||
K8S_COLLECTION_ERROR = None
|
||||
@@ -35,7 +43,6 @@ except ImportError as e:
|
||||
|
||||
|
||||
class AnsibleOpenshiftModule(AnsibleK8SModule):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(AnsibleOpenshiftModule, self).__init__(**kwargs)
|
||||
|
||||
@@ -86,7 +93,6 @@ class AnsibleOpenshiftModule(AnsibleK8SModule):
|
||||
return diff_objects(existing, new)
|
||||
|
||||
def run_module(self):
|
||||
|
||||
try:
|
||||
self.execute_module()
|
||||
except CoreException as e:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
@@ -23,62 +24,68 @@ def convert_storage_to_bytes(value):
|
||||
|
||||
|
||||
def is_valid_digest(digest):
|
||||
|
||||
digest_algorithm_size = dict(
|
||||
sha256=64, sha384=96, sha512=128,
|
||||
sha256=64,
|
||||
sha384=96,
|
||||
sha512=128,
|
||||
)
|
||||
|
||||
m = re.match(r'[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+', digest)
|
||||
m = re.match(r"[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+", digest)
|
||||
if not m:
|
||||
return "Docker digest does not match expected format %s" % digest
|
||||
|
||||
idx = digest.find(':')
|
||||
idx = digest.find(":")
|
||||
# case: "sha256:" with no hex.
|
||||
if idx < 0 or idx == (len(digest) - 1):
|
||||
return "Invalid docker digest %s, no hex value define" % digest
|
||||
|
||||
algorithm = digest[:idx]
|
||||
if algorithm not in digest_algorithm_size:
|
||||
return "Unsupported digest algorithm value %s for digest %s" % (algorithm, digest)
|
||||
return "Unsupported digest algorithm value %s for digest %s" % (
|
||||
algorithm,
|
||||
digest,
|
||||
)
|
||||
|
||||
hex_value = digest[idx + 1:]
|
||||
hex_value = digest[idx + 1:] # fmt: skip
|
||||
if len(hex_value) != digest_algorithm_size.get(algorithm):
|
||||
return "Invalid length for digest hex expected %d found %d (digest is %s)" % (
|
||||
digest_algorithm_size.get(algorithm), len(hex_value), digest
|
||||
digest_algorithm_size.get(algorithm),
|
||||
len(hex_value),
|
||||
digest,
|
||||
)
|
||||
|
||||
|
||||
def parse_docker_image_ref(image_ref, module=None):
|
||||
"""
|
||||
Docker Grammar Reference
|
||||
Reference => name [ ":" tag ] [ "@" digest ]
|
||||
name => [hostname '/'] component ['/' component]*
|
||||
hostname => hostcomponent ['.' hostcomponent]* [':' port-number]
|
||||
hostcomponent => /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||
port-number => /[0-9]+/
|
||||
component => alpha-numeric [separator alpha-numeric]*
|
||||
alpha-numeric => /[a-z0-9]+/
|
||||
separator => /[_.]|__|[-]*/
|
||||
Docker Grammar Reference
|
||||
Reference => name [ ":" tag ] [ "@" digest ]
|
||||
name => [hostname '/'] component ['/' component]*
|
||||
hostname => hostcomponent ['.' hostcomponent]* [':' port-number]
|
||||
hostcomponent => /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||
port-number => /[0-9]+/
|
||||
component => alpha-numeric [separator alpha-numeric]*
|
||||
alpha-numeric => /[a-z0-9]+/
|
||||
separator => /[_.]|__|[-]*/
|
||||
"""
|
||||
idx = image_ref.find("/")
|
||||
|
||||
def _contains_any(src, values):
|
||||
return any(x in src for x in values)
|
||||
|
||||
result = {
|
||||
"tag": None, "digest": None
|
||||
}
|
||||
result = {"tag": None, "digest": None}
|
||||
default_domain = "docker.io"
|
||||
if idx < 0 or (not _contains_any(image_ref[:idx], ":.") and image_ref[:idx] != "localhost"):
|
||||
if idx < 0 or (
|
||||
not _contains_any(image_ref[:idx], ":.") and image_ref[:idx] != "localhost"
|
||||
):
|
||||
result["hostname"], remainder = default_domain, image_ref
|
||||
else:
|
||||
result["hostname"], remainder = image_ref[:idx], image_ref[idx + 1:]
|
||||
result["hostname"], remainder = image_ref[:idx], image_ref[idx + 1:] # fmt: skip
|
||||
|
||||
# Parse remainder information
|
||||
idx = remainder.find("@")
|
||||
if idx > 0 and len(remainder) > (idx + 1):
|
||||
# docker image reference with digest
|
||||
component, result["digest"] = remainder[:idx], remainder[idx + 1:]
|
||||
component, result["digest"] = remainder[:idx], remainder[idx + 1:] # fmt: skip
|
||||
err = is_valid_digest(result["digest"])
|
||||
if err:
|
||||
if module:
|
||||
@@ -88,7 +95,7 @@ def parse_docker_image_ref(image_ref, module=None):
|
||||
idx = remainder.find(":")
|
||||
if idx > 0 and len(remainder) > (idx + 1):
|
||||
# docker image reference with tag
|
||||
component, result["tag"] = remainder[:idx], remainder[idx + 1:]
|
||||
component, result["tag"] = remainder[:idx], remainder[idx + 1:] # fmt: skip
|
||||
else:
|
||||
# name only
|
||||
component = remainder
|
||||
@@ -96,8 +103,6 @@ def parse_docker_image_ref(image_ref, module=None):
|
||||
namespace = None
|
||||
if len(v) > 1:
|
||||
namespace = v[0]
|
||||
result.update({
|
||||
"namespace": namespace, "name": v[-1]
|
||||
})
|
||||
result.update({"namespace": namespace, "name": v[-1]})
|
||||
|
||||
return result, None
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
@@ -19,18 +19,21 @@ from ansible_collections.community.okd.plugins.module_utils.openshift_ldap impor
|
||||
ldap_split_host_port,
|
||||
OpenshiftLDAPRFC2307,
|
||||
OpenshiftLDAPActiveDirectory,
|
||||
OpenshiftLDAPAugmentedActiveDirectory
|
||||
OpenshiftLDAPAugmentedActiveDirectory,
|
||||
)
|
||||
|
||||
try:
|
||||
import ldap
|
||||
|
||||
HAS_PYTHON_LDAP = True
|
||||
PYTHON_LDAP_ERROR = None
|
||||
except ImportError as e:
|
||||
HAS_PYTHON_LDAP = False
|
||||
PYTHON_LDAP_ERROR = e
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -44,7 +47,9 @@ LDAP_OPENSHIFT_UID_ANNOTATION = "openshift.io/ldap.uid"
|
||||
LDAP_OPENSHIFT_SYNCTIME_ANNOTATION = "openshift.io/ldap.sync-time"
|
||||
|
||||
|
||||
def connect_to_ldap(module, server_uri, bind_dn=None, bind_pw=None, insecure=True, ca_file=None):
|
||||
def connect_to_ldap(
|
||||
module, server_uri, bind_dn=None, bind_pw=None, insecure=True, ca_file=None
|
||||
):
|
||||
if insecure:
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
elif ca_file:
|
||||
@@ -56,27 +61,36 @@ def connect_to_ldap(module, server_uri, bind_dn=None, bind_pw=None, insecure=Tru
|
||||
connection.simple_bind_s(bind_dn, bind_pw)
|
||||
return connection
|
||||
except ldap.LDAPError as e:
|
||||
module.fail_json(msg="Cannot bind to the LDAP server '{0}' due to: {1}".format(server_uri, e))
|
||||
module.fail_json(
|
||||
msg="Cannot bind to the LDAP server '{0}' due to: {1}".format(server_uri, e)
|
||||
)
|
||||
|
||||
|
||||
def validate_group_annotation(definition, host_ip):
|
||||
name = definition['metadata']['name']
|
||||
name = definition["metadata"]["name"]
|
||||
# Validate LDAP URL Annotation
|
||||
annotate_url = definition['metadata'].get('annotations', {}).get(LDAP_OPENSHIFT_URL_ANNOTATION)
|
||||
annotate_url = (
|
||||
definition["metadata"].get("annotations", {}).get(LDAP_OPENSHIFT_URL_ANNOTATION)
|
||||
)
|
||||
if host_ip:
|
||||
if not annotate_url:
|
||||
return "group '{0}' marked as having been synced did not have an '{1}' annotation".format(name, LDAP_OPENSHIFT_URL_ANNOTATION)
|
||||
return "group '{0}' marked as having been synced did not have an '{1}' annotation".format(
|
||||
name, LDAP_OPENSHIFT_URL_ANNOTATION
|
||||
)
|
||||
elif annotate_url != host_ip:
|
||||
return "group '{0}' was not synchronized from: '{1}'".format(name, host_ip)
|
||||
# Validate LDAP UID Annotation
|
||||
annotate_uid = definition['metadata']['annotations'].get(LDAP_OPENSHIFT_UID_ANNOTATION)
|
||||
annotate_uid = definition["metadata"]["annotations"].get(
|
||||
LDAP_OPENSHIFT_UID_ANNOTATION
|
||||
)
|
||||
if not annotate_uid:
|
||||
return "group '{0}' marked as having been synced did not have an '{1}' annotation".format(name, LDAP_OPENSHIFT_UID_ANNOTATION)
|
||||
return "group '{0}' marked as having been synced did not have an '{1}' annotation".format(
|
||||
name, LDAP_OPENSHIFT_UID_ANNOTATION
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
class OpenshiftLDAPGroups(object):
|
||||
|
||||
kind = "Group"
|
||||
version = "user.openshift.io/v1"
|
||||
|
||||
@@ -88,11 +102,7 @@ class OpenshiftLDAPGroups(object):
|
||||
@property
|
||||
def k8s_group_api(self):
|
||||
if not self.__group_api:
|
||||
params = dict(
|
||||
kind=self.kind,
|
||||
api_version=self.version,
|
||||
fail=True
|
||||
)
|
||||
params = dict(kind=self.kind, api_version=self.version, fail=True)
|
||||
self.__group_api = self.module.find_resource(**params)
|
||||
return self.__group_api
|
||||
|
||||
@@ -139,16 +149,26 @@ class OpenshiftLDAPGroups(object):
|
||||
|
||||
if missing:
|
||||
self.module.fail_json(
|
||||
msg="The following groups were not found: %s" % ''.join(missing)
|
||||
msg="The following groups were not found: %s" % "".join(missing)
|
||||
)
|
||||
else:
|
||||
label_selector = "%s=%s" % (LDAP_OPENSHIFT_HOST_LABEL, host)
|
||||
resources = self.get_group_info(label_selectors=[label_selector], return_list=True)
|
||||
resources = self.get_group_info(
|
||||
label_selectors=[label_selector], return_list=True
|
||||
)
|
||||
if not resources:
|
||||
return None, "Unable to find Group matching label selector '%s'" % label_selector
|
||||
return (
|
||||
None,
|
||||
"Unable to find Group matching label selector '%s'"
|
||||
% label_selector,
|
||||
)
|
||||
groups = resources
|
||||
if deny_groups:
|
||||
groups = [item for item in groups if item["metadata"]["name"] not in deny_groups]
|
||||
groups = [
|
||||
item
|
||||
for item in groups
|
||||
if item["metadata"]["name"] not in deny_groups
|
||||
]
|
||||
|
||||
uids = []
|
||||
for grp in groups:
|
||||
@@ -156,7 +176,9 @@ class OpenshiftLDAPGroups(object):
|
||||
if err and allow_groups:
|
||||
# We raise an error for group part of the allow_group not matching LDAP sync criteria
|
||||
return None, err
|
||||
group_uid = grp['metadata']['annotations'].get(LDAP_OPENSHIFT_UID_ANNOTATION)
|
||||
group_uid = grp["metadata"]["annotations"].get(
|
||||
LDAP_OPENSHIFT_UID_ANNOTATION
|
||||
)
|
||||
self.cache[group_uid] = grp
|
||||
uids.append(group_uid)
|
||||
return uids, None
|
||||
@@ -174,38 +196,65 @@ class OpenshiftLDAPGroups(object):
|
||||
"kind": "Group",
|
||||
"metadata": {
|
||||
"name": group_name,
|
||||
"labels": {
|
||||
LDAP_OPENSHIFT_HOST_LABEL: self.module.host
|
||||
},
|
||||
"labels": {LDAP_OPENSHIFT_HOST_LABEL: self.module.host},
|
||||
"annotations": {
|
||||
LDAP_OPENSHIFT_URL_ANNOTATION: self.module.netlocation,
|
||||
LDAP_OPENSHIFT_UID_ANNOTATION: group_uid,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Make sure we aren't taking over an OpenShift group that is already related to a different LDAP group
|
||||
ldaphost_label = group["metadata"].get("labels", {}).get(LDAP_OPENSHIFT_HOST_LABEL)
|
||||
ldaphost_label = (
|
||||
group["metadata"].get("labels", {}).get(LDAP_OPENSHIFT_HOST_LABEL)
|
||||
)
|
||||
if not ldaphost_label or ldaphost_label != self.module.host:
|
||||
return None, "Group %s: %s label did not match sync host: wanted %s, got %s" % (
|
||||
group_name, LDAP_OPENSHIFT_HOST_LABEL, self.module.host, ldaphost_label
|
||||
return (
|
||||
None,
|
||||
"Group %s: %s label did not match sync host: wanted %s, got %s"
|
||||
% (
|
||||
group_name,
|
||||
LDAP_OPENSHIFT_HOST_LABEL,
|
||||
self.module.host,
|
||||
ldaphost_label,
|
||||
),
|
||||
)
|
||||
|
||||
ldapurl_annotation = group["metadata"].get("annotations", {}).get(LDAP_OPENSHIFT_URL_ANNOTATION)
|
||||
ldapurl_annotation = (
|
||||
group["metadata"].get("annotations", {}).get(LDAP_OPENSHIFT_URL_ANNOTATION)
|
||||
)
|
||||
if not ldapurl_annotation or ldapurl_annotation != self.module.netlocation:
|
||||
return None, "Group %s: %s annotation did not match sync host: wanted %s, got %s" % (
|
||||
group_name, LDAP_OPENSHIFT_URL_ANNOTATION, self.module.netlocation, ldapurl_annotation
|
||||
return (
|
||||
None,
|
||||
"Group %s: %s annotation did not match sync host: wanted %s, got %s"
|
||||
% (
|
||||
group_name,
|
||||
LDAP_OPENSHIFT_URL_ANNOTATION,
|
||||
self.module.netlocation,
|
||||
ldapurl_annotation,
|
||||
),
|
||||
)
|
||||
|
||||
ldapuid_annotation = group["metadata"].get("annotations", {}).get(LDAP_OPENSHIFT_UID_ANNOTATION)
|
||||
ldapuid_annotation = (
|
||||
group["metadata"].get("annotations", {}).get(LDAP_OPENSHIFT_UID_ANNOTATION)
|
||||
)
|
||||
if not ldapuid_annotation or ldapuid_annotation != group_uid:
|
||||
return None, "Group %s: %s annotation did not match LDAP UID: wanted %s, got %s" % (
|
||||
group_name, LDAP_OPENSHIFT_UID_ANNOTATION, group_uid, ldapuid_annotation
|
||||
return (
|
||||
None,
|
||||
"Group %s: %s annotation did not match LDAP UID: wanted %s, got %s"
|
||||
% (
|
||||
group_name,
|
||||
LDAP_OPENSHIFT_UID_ANNOTATION,
|
||||
group_uid,
|
||||
ldapuid_annotation,
|
||||
),
|
||||
)
|
||||
|
||||
# Overwrite Group Users data
|
||||
group["users"] = usernames
|
||||
group["metadata"]["annotations"][LDAP_OPENSHIFT_SYNCTIME_ANNOTATION] = datetime.now().isoformat()
|
||||
group["metadata"]["annotations"][
|
||||
LDAP_OPENSHIFT_SYNCTIME_ANNOTATION
|
||||
] = datetime.now().isoformat()
|
||||
return group, None
|
||||
|
||||
def create_openshift_groups(self, groups: list):
|
||||
@@ -223,9 +272,15 @@ class OpenshiftLDAPGroups(object):
|
||||
else:
|
||||
definition = self.k8s_group_api.create(definition).to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.module.fail_json(msg="Failed to %s Group '%s' due to: %s" % (method, name, exc.body))
|
||||
self.module.fail_json(
|
||||
msg="Failed to %s Group '%s' due to: %s"
|
||||
% (method, name, exc.body)
|
||||
)
|
||||
except Exception as exc:
|
||||
self.module.fail_json(msg="Failed to %s Group '%s' due to: %s" % (method, name, to_native(exc)))
|
||||
self.module.fail_json(
|
||||
msg="Failed to %s Group '%s' due to: %s"
|
||||
% (method, name, to_native(exc))
|
||||
)
|
||||
equals = False
|
||||
if existing:
|
||||
equals, diff = self.module.diff_objects(existing, definition)
|
||||
@@ -235,27 +290,27 @@ class OpenshiftLDAPGroups(object):
|
||||
return results, diffs, changed
|
||||
|
||||
def delete_openshift_group(self, name: str):
|
||||
result = dict(
|
||||
kind=self.kind,
|
||||
apiVersion=self.version,
|
||||
metadata=dict(
|
||||
name=name
|
||||
)
|
||||
)
|
||||
result = dict(kind=self.kind, apiVersion=self.version, metadata=dict(name=name))
|
||||
if not self.module.check_mode:
|
||||
try:
|
||||
result = self.k8s_group_api.delete(name=name).to_dict()
|
||||
except DynamicApiError as exc:
|
||||
self.module.fail_json(msg="Failed to delete Group '{0}' due to: {1}".format(name, exc.body))
|
||||
self.module.fail_json(
|
||||
msg="Failed to delete Group '{0}' due to: {1}".format(
|
||||
name, exc.body
|
||||
)
|
||||
)
|
||||
except Exception as exc:
|
||||
self.module.fail_json(msg="Failed to delete Group '{0}' due to: {1}".format(name, to_native(exc)))
|
||||
self.module.fail_json(
|
||||
msg="Failed to delete Group '{0}' due to: {1}".format(
|
||||
name, to_native(exc)
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super(OpenshiftGroupsSync, self).__init__(**kwargs)
|
||||
self.__k8s_group_api = None
|
||||
self.__ldap_connection = None
|
||||
@@ -267,17 +322,14 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
|
||||
if not HAS_PYTHON_LDAP:
|
||||
self.fail_json(
|
||||
msg=missing_required_lib('python-ldap'), error=to_native(PYTHON_LDAP_ERROR)
|
||||
msg=missing_required_lib("python-ldap"),
|
||||
error=to_native(PYTHON_LDAP_ERROR),
|
||||
)
|
||||
|
||||
@property
|
||||
def k8s_group_api(self):
|
||||
if not self.__k8s_group_api:
|
||||
params = dict(
|
||||
kind="Group",
|
||||
api_version="user.openshift.io/v1",
|
||||
fail=True
|
||||
)
|
||||
params = dict(kind="Group", api_version="user.openshift.io/v1", fail=True)
|
||||
self.__k8s_group_api = self.find_resource(**params)
|
||||
return self.__k8s_group_api
|
||||
|
||||
@@ -291,11 +343,11 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
# Create connection object
|
||||
params = dict(
|
||||
module=self,
|
||||
server_uri=self.config.get('url'),
|
||||
bind_dn=self.config.get('bindDN'),
|
||||
bind_pw=self.config.get('bindPassword'),
|
||||
insecure=boolean(self.config.get('insecure')),
|
||||
ca_file=self.config.get('ca')
|
||||
server_uri=self.config.get("url"),
|
||||
bind_dn=self.config.get("bindDN"),
|
||||
bind_pw=self.config.get("bindPassword"),
|
||||
insecure=boolean(self.config.get("insecure")),
|
||||
ca_file=self.config.get("ca"),
|
||||
)
|
||||
self.__ldap_connection = connect_to_ldap(**params)
|
||||
return self.__ldap_connection
|
||||
@@ -327,7 +379,6 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
return syncer
|
||||
|
||||
def synchronize(self):
|
||||
|
||||
sync_group_type = self.module.params.get("type")
|
||||
|
||||
groups_uids = []
|
||||
@@ -365,7 +416,8 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
name, err = syncer.get_username_for_entry(entry)
|
||||
if err:
|
||||
self.exit_json(
|
||||
msg="Unable to determine username for entry %s: %s" % (entry, err)
|
||||
msg="Unable to determine username for entry %s: %s"
|
||||
% (entry, err)
|
||||
)
|
||||
if isinstance(name, list):
|
||||
usernames.extend(name)
|
||||
@@ -380,13 +432,17 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
self.exit_json(msg=err)
|
||||
|
||||
# Make Openshift group
|
||||
group, err = ldap_openshift_group.make_openshift_group(uid, group_name, usernames)
|
||||
group, err = ldap_openshift_group.make_openshift_group(
|
||||
uid, group_name, usernames
|
||||
)
|
||||
if err:
|
||||
self.fail_json(msg=err)
|
||||
openshift_groups.append(group)
|
||||
|
||||
# Create Openshift Groups
|
||||
results, diffs, changed = ldap_openshift_group.create_openshift_groups(openshift_groups)
|
||||
results, diffs, changed = ldap_openshift_group.create_openshift_groups(
|
||||
openshift_groups
|
||||
)
|
||||
self.module.exit_json(changed=True, groups=results)
|
||||
|
||||
def prune(self):
|
||||
@@ -404,7 +460,10 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
# Check if LDAP group exist
|
||||
exists, err = syncer.is_ldapgroup_exists(uid)
|
||||
if err:
|
||||
msg = "Error determining LDAP group existence for group %s: %s" % (uid, err)
|
||||
msg = "Error determining LDAP group existence for group %s: %s" % (
|
||||
uid,
|
||||
err,
|
||||
)
|
||||
self.module.fail_json(msg=msg)
|
||||
|
||||
if exists:
|
||||
@@ -429,14 +488,22 @@ class OpenshiftGroupsSync(AnsibleOpenshiftModule):
|
||||
self.fail_json(msg="Invalid LDAP Sync config: %s" % error)
|
||||
|
||||
# Split host/port
|
||||
if self.config.get('url'):
|
||||
result, error = ldap_split_host_port(self.config.get('url'))
|
||||
if self.config.get("url"):
|
||||
result, error = ldap_split_host_port(self.config.get("url"))
|
||||
if error:
|
||||
self.fail_json(msg="Failed to parse url='{0}': {1}".format(self.config.get('url'), error))
|
||||
self.netlocation, self.host, self.port = result["netlocation"], result["host"], result["port"]
|
||||
self.fail_json(
|
||||
msg="Failed to parse url='{0}': {1}".format(
|
||||
self.config.get("url"), error
|
||||
)
|
||||
)
|
||||
self.netlocation, self.host, self.port = (
|
||||
result["netlocation"],
|
||||
result["host"],
|
||||
result["port"],
|
||||
)
|
||||
self.scheme = result["scheme"]
|
||||
|
||||
if self.params.get('state') == 'present':
|
||||
if self.params.get("state") == "present":
|
||||
self.synchronize()
|
||||
else:
|
||||
self.prune()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from datetime import datetime
|
||||
@@ -17,9 +18,9 @@ def get_image_blobs(image):
|
||||
return blobs, "failed to read metadata for image %s" % image["metadata"]["name"]
|
||||
media_type_manifest = (
|
||||
"application/vnd.docker.distribution.manifest.v2+json",
|
||||
"application/vnd.oci.image.manifest.v1+json"
|
||||
"application/vnd.oci.image.manifest.v1+json",
|
||||
)
|
||||
media_type_has_config = image['dockerImageManifestMediaType'] in media_type_manifest
|
||||
media_type_has_config = image["dockerImageManifestMediaType"] in media_type_manifest
|
||||
docker_image_id = docker_image_metadata.get("Id")
|
||||
if media_type_has_config and docker_image_id and len(docker_image_id) > 0:
|
||||
blobs.append(docker_image_id)
|
||||
@@ -29,19 +30,18 @@ def get_image_blobs(image):
|
||||
def is_created_after(creation_timestamp, max_creation_timestamp):
|
||||
if not max_creation_timestamp:
|
||||
return False
|
||||
creationTimestamp = datetime.strptime(creation_timestamp, '%Y-%m-%dT%H:%M:%SZ')
|
||||
creationTimestamp = datetime.strptime(creation_timestamp, "%Y-%m-%dT%H:%M:%SZ")
|
||||
return creationTimestamp > max_creation_timestamp
|
||||
|
||||
|
||||
def is_too_young_object(obj, max_creation_timestamp):
|
||||
return is_created_after(obj['metadata']['creationTimestamp'],
|
||||
max_creation_timestamp)
|
||||
return is_created_after(
|
||||
obj["metadata"]["creationTimestamp"], max_creation_timestamp
|
||||
)
|
||||
|
||||
|
||||
class OpenShiftAnalyzeImageStream(object):
|
||||
|
||||
def __init__(self, ignore_invalid_refs, max_creation_timestamp, module):
|
||||
|
||||
self.max_creationTimestamp = max_creation_timestamp
|
||||
self.used_tags = {}
|
||||
self.used_images = {}
|
||||
@@ -53,32 +53,34 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
if error:
|
||||
return error
|
||||
|
||||
if not result['hostname'] or not result['namespace']:
|
||||
if not result["hostname"] or not result["namespace"]:
|
||||
# image reference does not match hostname/namespace/name pattern - skipping
|
||||
return None
|
||||
|
||||
if not result['digest']:
|
||||
if not result["digest"]:
|
||||
# Attempt to dereference istag. Since we cannot be sure whether the reference refers to the
|
||||
# integrated registry or not, we ignore the host part completely. As a consequence, we may keep
|
||||
# image otherwise sentenced for a removal just because its pull spec accidentally matches one of
|
||||
# our imagestreamtags.
|
||||
|
||||
# set the tag if empty
|
||||
if result['tag'] == "":
|
||||
result['tag'] = 'latest'
|
||||
key = "%s/%s:%s" % (result['namespace'], result['name'], result['tag'])
|
||||
if result["tag"] == "":
|
||||
result["tag"] = "latest"
|
||||
key = "%s/%s:%s" % (result["namespace"], result["name"], result["tag"])
|
||||
if key not in self.used_tags:
|
||||
self.used_tags[key] = []
|
||||
self.used_tags[key].append(referrer)
|
||||
else:
|
||||
key = "%s/%s@%s" % (result['namespace'], result['name'], result['digest'])
|
||||
key = "%s/%s@%s" % (result["namespace"], result["name"], result["digest"])
|
||||
if key not in self.used_images:
|
||||
self.used_images[key] = []
|
||||
self.used_images[key].append(referrer)
|
||||
|
||||
def analyze_refs_from_pod_spec(self, podSpec, referrer):
|
||||
for container in podSpec.get('initContainers', []) + podSpec.get('containers', []):
|
||||
image = container.get('image')
|
||||
for container in podSpec.get("initContainers", []) + podSpec.get(
|
||||
"containers", []
|
||||
):
|
||||
image = container.get("image")
|
||||
if len(image.strip()) == 0:
|
||||
# Ignoring container because it has no reference to image
|
||||
continue
|
||||
@@ -93,29 +95,35 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
# pending or running. Additionally, it has to be at least as old as the minimum
|
||||
# age threshold defined by the algorithm.
|
||||
too_young = is_too_young_object(pod, self.max_creationTimestamp)
|
||||
if pod['status']['phase'] not in ("Running", "Pending") and too_young:
|
||||
if pod["status"]["phase"] not in ("Running", "Pending") and too_young:
|
||||
continue
|
||||
referrer = {
|
||||
"kind": pod["kind"],
|
||||
"namespace": pod["metadata"]["namespace"],
|
||||
"name": pod["metadata"]["name"],
|
||||
}
|
||||
err = self.analyze_refs_from_pod_spec(pod['spec'], referrer)
|
||||
err = self.analyze_refs_from_pod_spec(pod["spec"], referrer)
|
||||
if err:
|
||||
return err
|
||||
return None
|
||||
|
||||
def analyze_refs_pod_creators(self, resources):
|
||||
keys = (
|
||||
"ReplicationController", "DeploymentConfig", "DaemonSet",
|
||||
"Deployment", "ReplicaSet", "StatefulSet", "Job", "CronJob"
|
||||
"ReplicationController",
|
||||
"DeploymentConfig",
|
||||
"DaemonSet",
|
||||
"Deployment",
|
||||
"ReplicaSet",
|
||||
"StatefulSet",
|
||||
"Job",
|
||||
"CronJob",
|
||||
)
|
||||
|
||||
for k, objects in iteritems(resources):
|
||||
if k not in keys:
|
||||
continue
|
||||
for obj in objects:
|
||||
if k == 'CronJob':
|
||||
if k == "CronJob":
|
||||
spec = obj["spec"]["jobTemplate"]["spec"]["template"]["spec"]
|
||||
else:
|
||||
spec = obj["spec"]["template"]["spec"]
|
||||
@@ -132,64 +140,84 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
def analyze_refs_from_strategy(self, build_strategy, namespace, referrer):
|
||||
# Determine 'from' reference
|
||||
def _determine_source_strategy():
|
||||
for src in ('sourceStrategy', 'dockerStrategy', 'customStrategy'):
|
||||
for src in ("sourceStrategy", "dockerStrategy", "customStrategy"):
|
||||
strategy = build_strategy.get(src)
|
||||
if strategy:
|
||||
return strategy.get('from')
|
||||
return strategy.get("from")
|
||||
return None
|
||||
|
||||
def _parse_image_stream_image_name(name):
|
||||
v = name.split('@')
|
||||
v = name.split("@")
|
||||
if len(v) != 2:
|
||||
return None, None, "expected exactly one @ in the isimage name %s" % name
|
||||
return (
|
||||
None,
|
||||
None,
|
||||
"expected exactly one @ in the isimage name %s" % name,
|
||||
)
|
||||
name = v[0]
|
||||
tag = v[1]
|
||||
if len(name) == 0 or len(tag) == 0:
|
||||
return None, None, "image stream image name %s must have a name and ID" % name
|
||||
return (
|
||||
None,
|
||||
None,
|
||||
"image stream image name %s must have a name and ID" % name,
|
||||
)
|
||||
return name, tag, None
|
||||
|
||||
def _parse_image_stream_tag_name(name):
|
||||
if "@" in name:
|
||||
return None, None, "%s is an image stream image, not an image stream tag" % name
|
||||
return (
|
||||
None,
|
||||
None,
|
||||
"%s is an image stream image, not an image stream tag" % name,
|
||||
)
|
||||
v = name.split(":")
|
||||
if len(v) != 2:
|
||||
return None, None, "expected exactly one : delimiter in the istag %s" % name
|
||||
return (
|
||||
None,
|
||||
None,
|
||||
"expected exactly one : delimiter in the istag %s" % name,
|
||||
)
|
||||
name = v[0]
|
||||
tag = v[1]
|
||||
if len(name) == 0 or len(tag) == 0:
|
||||
return None, None, "image stream tag name %s must have a name and a tag" % name
|
||||
return (
|
||||
None,
|
||||
None,
|
||||
"image stream tag name %s must have a name and a tag" % name,
|
||||
)
|
||||
return name, tag, None
|
||||
|
||||
from_strategy = _determine_source_strategy()
|
||||
if from_strategy:
|
||||
if from_strategy.get('kind') == "DockerImage":
|
||||
docker_image_ref = from_strategy.get('name').strip()
|
||||
if from_strategy.get("kind") == "DockerImage":
|
||||
docker_image_ref = from_strategy.get("name").strip()
|
||||
if len(docker_image_ref) > 0:
|
||||
err = self.analyze_reference_image(docker_image_ref, referrer)
|
||||
elif from_strategy.get('kind') == "ImageStreamImage":
|
||||
name, tag, error = _parse_image_stream_image_name(from_strategy.get('name'))
|
||||
elif from_strategy.get("kind") == "ImageStreamImage":
|
||||
name, tag, error = _parse_image_stream_image_name(
|
||||
from_strategy.get("name")
|
||||
)
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_images.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
elif from_strategy.get('kind') == "ImageStreamTag":
|
||||
name, tag, error = _parse_image_stream_tag_name(from_strategy.get('name'))
|
||||
namespace = from_strategy.get("namespace") or namespace
|
||||
self.used_images.append(
|
||||
{"namespace": namespace, "name": name, "tag": tag}
|
||||
)
|
||||
elif from_strategy.get("kind") == "ImageStreamTag":
|
||||
name, tag, error = _parse_image_stream_tag_name(
|
||||
from_strategy.get("name")
|
||||
)
|
||||
if error:
|
||||
if not self.ignore_invalid_refs:
|
||||
return error
|
||||
else:
|
||||
namespace = from_strategy.get('namespace') or namespace
|
||||
self.used_tags.append({
|
||||
'namespace': namespace,
|
||||
'name': name,
|
||||
'tag': tag
|
||||
})
|
||||
namespace = from_strategy.get("namespace") or namespace
|
||||
self.used_tags.append(
|
||||
{"namespace": namespace, "name": name, "tag": tag}
|
||||
)
|
||||
|
||||
def analyze_refs_from_build_strategy(self, resources):
|
||||
# Json Path is always spec.strategy
|
||||
@@ -203,16 +231,20 @@ class OpenShiftAnalyzeImageStream(object):
|
||||
"namespace": obj["metadata"]["namespace"],
|
||||
"name": obj["metadata"]["name"],
|
||||
}
|
||||
error = self.analyze_refs_from_strategy(obj['spec']['strategy'],
|
||||
obj['metadata']['namespace'],
|
||||
referrer)
|
||||
error = self.analyze_refs_from_strategy(
|
||||
obj["spec"]["strategy"], obj["metadata"]["namespace"], referrer
|
||||
)
|
||||
if error is not None:
|
||||
return "%s/%s/%s: %s" % (referrer["kind"], referrer["namespace"], referrer["name"], error)
|
||||
return "%s/%s/%s: %s" % (
|
||||
referrer["kind"],
|
||||
referrer["namespace"],
|
||||
referrer["name"],
|
||||
error,
|
||||
)
|
||||
|
||||
def analyze_image_stream(self, resources):
|
||||
|
||||
# Analyze image reference from Pods
|
||||
error = self.analyze_refs_from_pods(resources['Pod'])
|
||||
error = self.analyze_refs_from_pods(resources["Pod"])
|
||||
if error:
|
||||
return None, None, error
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
import copy
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -44,10 +45,17 @@ def follow_imagestream_tag_reference(stream, tag):
|
||||
return name, tag, len(parts) == 2
|
||||
|
||||
content = []
|
||||
err_cross_stream_ref = "tag %s points to an imagestreamtag from another ImageStream" % tag
|
||||
err_cross_stream_ref = (
|
||||
"tag %s points to an imagestreamtag from another ImageStream" % tag
|
||||
)
|
||||
while True:
|
||||
if tag in content:
|
||||
return tag, None, multiple, "tag %s on the image stream is a reference to same tag" % tag
|
||||
return (
|
||||
tag,
|
||||
None,
|
||||
multiple,
|
||||
"tag %s on the image stream is a reference to same tag" % tag,
|
||||
)
|
||||
content.append(tag)
|
||||
tag_ref = _imagestream_has_tag()
|
||||
if not tag_ref:
|
||||
@@ -56,7 +64,10 @@ def follow_imagestream_tag_reference(stream, tag):
|
||||
if not tag_ref.get("from") or tag_ref["from"]["kind"] != "ImageStreamTag":
|
||||
return tag, tag_ref, multiple, None
|
||||
|
||||
if tag_ref["from"]["namespace"] != "" and tag_ref["from"]["namespace"] != stream["metadata"]["namespace"]:
|
||||
if (
|
||||
tag_ref["from"]["namespace"] != ""
|
||||
and tag_ref["from"]["namespace"] != stream["metadata"]["namespace"]
|
||||
):
|
||||
return tag, None, multiple, err_cross_stream_ref
|
||||
|
||||
# The reference needs to be followed with two format patterns:
|
||||
@@ -64,7 +75,12 @@ def follow_imagestream_tag_reference(stream, tag):
|
||||
if ":" in tag_ref["from"]["name"]:
|
||||
name, tagref, result = _imagestream_split_tag(tag_ref["from"]["name"])
|
||||
if not result:
|
||||
return tag, None, multiple, "tag %s points to an invalid imagestreamtag" % tag
|
||||
return (
|
||||
tag,
|
||||
None,
|
||||
multiple,
|
||||
"tag %s points to an invalid imagestreamtag" % tag,
|
||||
)
|
||||
if name != stream["metadata"]["namespace"]:
|
||||
# anotheris:sometag - this should not happen.
|
||||
return tag, None, multiple, err_cross_stream_ref
|
||||
@@ -80,7 +96,7 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
super(OpenShiftImportImage, self).__init__(**kwargs)
|
||||
|
||||
self._rest_client = None
|
||||
self.registryhost = self.params.get('registry_url')
|
||||
self.registryhost = self.params.get("registry_url")
|
||||
self.changed = False
|
||||
|
||||
ref_policy = self.params.get("reference_policy")
|
||||
@@ -90,9 +106,7 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
elif ref_policy == "local":
|
||||
ref_policy_type = "Local"
|
||||
|
||||
self.ref_policy = {
|
||||
"type": ref_policy_type
|
||||
}
|
||||
self.ref_policy = {"type": ref_policy_type}
|
||||
|
||||
self.validate_certs = self.params.get("validate_registry_certs")
|
||||
self.cluster_resources = {}
|
||||
@@ -104,15 +118,15 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
"metadata": {
|
||||
"name": stream["metadata"]["name"],
|
||||
"namespace": stream["metadata"]["namespace"],
|
||||
"resourceVersion": stream["metadata"].get("resourceVersion")
|
||||
"resourceVersion": stream["metadata"].get("resourceVersion"),
|
||||
},
|
||||
"spec": {
|
||||
"import": True
|
||||
}
|
||||
"spec": {"import": True},
|
||||
}
|
||||
|
||||
annotations = stream.get("annotations", {})
|
||||
insecure = boolean(annotations.get("openshift.io/image.insecureRepository", True))
|
||||
insecure = boolean(
|
||||
annotations.get("openshift.io/image.insecureRepository", True)
|
||||
)
|
||||
if self.validate_certs is not None:
|
||||
insecure = not self.validate_certs
|
||||
return isi, insecure
|
||||
@@ -126,7 +140,7 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
},
|
||||
"importPolicy": {
|
||||
"insecure": insecure,
|
||||
"scheduled": self.params.get("scheduled")
|
||||
"scheduled": self.params.get("scheduled"),
|
||||
},
|
||||
"referencePolicy": self.ref_policy,
|
||||
}
|
||||
@@ -149,26 +163,23 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
scheduled = scheduled or old_tag["importPolicy"].get("scheduled")
|
||||
|
||||
images = isi["spec"].get("images", [])
|
||||
images.append({
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": tags.get(k),
|
||||
},
|
||||
"to": {
|
||||
"name": k
|
||||
},
|
||||
"importPolicy": {
|
||||
"insecure": insecure,
|
||||
"scheduled": scheduled
|
||||
},
|
||||
"referencePolicy": self.ref_policy,
|
||||
})
|
||||
images.append(
|
||||
{
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": tags.get(k),
|
||||
},
|
||||
"to": {"name": k},
|
||||
"importPolicy": {"insecure": insecure, "scheduled": scheduled},
|
||||
"referencePolicy": self.ref_policy,
|
||||
}
|
||||
)
|
||||
isi["spec"]["images"] = images
|
||||
return isi
|
||||
|
||||
def create_image_stream(self, ref):
|
||||
"""
|
||||
Create new ImageStream and accompanying ImageStreamImport
|
||||
Create new ImageStream and accompanying ImageStreamImport
|
||||
"""
|
||||
source = self.params.get("source")
|
||||
if not source:
|
||||
@@ -183,27 +194,20 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
),
|
||||
)
|
||||
if self.params.get("all") and not ref["tag"]:
|
||||
spec = dict(
|
||||
dockerImageRepository=source
|
||||
)
|
||||
spec = dict(dockerImageRepository=source)
|
||||
isi = self.create_image_stream_import_all(stream, source)
|
||||
else:
|
||||
spec = dict(
|
||||
tags=[
|
||||
{
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": source
|
||||
},
|
||||
"referencePolicy": self.ref_policy
|
||||
"from": {"kind": "DockerImage", "name": source},
|
||||
"referencePolicy": self.ref_policy,
|
||||
}
|
||||
]
|
||||
)
|
||||
tags = {ref["tag"]: source}
|
||||
isi = self.create_image_stream_import_tags(stream, tags)
|
||||
stream.update(
|
||||
dict(spec=spec)
|
||||
)
|
||||
stream.update(dict(spec=spec))
|
||||
return stream, isi
|
||||
|
||||
def import_all(self, istream):
|
||||
@@ -220,8 +224,9 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
if t.get("from") and t["from"].get("kind") == "DockerImage":
|
||||
tags[t.get("name")] = t["from"].get("name")
|
||||
if tags == {}:
|
||||
msg = "image stream %s/%s does not have tags pointing to external container images" % (
|
||||
stream["metadata"]["namespace"], stream["metadata"]["name"]
|
||||
msg = (
|
||||
"image stream %s/%s does not have tags pointing to external container images"
|
||||
% (stream["metadata"]["namespace"], stream["metadata"]["name"])
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
isi = self.create_image_stream_import_tags(stream, tags)
|
||||
@@ -236,7 +241,9 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
source = self.params.get("source")
|
||||
|
||||
# Follow any referential tags to the destination
|
||||
final_tag, existing, multiple, err = follow_imagestream_tag_reference(stream, tag)
|
||||
final_tag, existing, multiple, err = follow_imagestream_tag_reference(
|
||||
stream, tag
|
||||
)
|
||||
if err:
|
||||
if err == err_stream_not_found_ref:
|
||||
# Create a new tag
|
||||
@@ -245,7 +252,10 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
# if the from is still empty this means there's no such tag defined
|
||||
# nor we can't create any from .spec.dockerImageRepository
|
||||
if not source:
|
||||
msg = "the tag %s does not exist on the image stream - choose an existing tag to import" % tag
|
||||
msg = (
|
||||
"the tag %s does not exist on the image stream - choose an existing tag to import"
|
||||
% tag
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
existing = {
|
||||
"from": {
|
||||
@@ -257,13 +267,21 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
self.fail_json(msg=err)
|
||||
else:
|
||||
# Disallow re-importing anything other than DockerImage
|
||||
if existing.get("from", {}) and existing["from"].get("kind") != "DockerImage":
|
||||
if (
|
||||
existing.get("from", {})
|
||||
and existing["from"].get("kind") != "DockerImage"
|
||||
):
|
||||
msg = "tag {tag} points to existing {kind}/={name}, it cannot be re-imported.".format(
|
||||
tag=tag, kind=existing["from"]["kind"], name=existing["from"]["name"]
|
||||
tag=tag,
|
||||
kind=existing["from"]["kind"],
|
||||
name=existing["from"]["name"],
|
||||
)
|
||||
# disallow changing an existing tag
|
||||
if not existing.get("from", {}):
|
||||
msg = "tag %s already exists - you cannot change the source using this module." % tag
|
||||
msg = (
|
||||
"tag %s already exists - you cannot change the source using this module."
|
||||
% tag
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
if source and source != existing["from"]["name"]:
|
||||
if multiple:
|
||||
@@ -271,7 +289,10 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
tag, final_tag, existing["from"]["name"]
|
||||
)
|
||||
else:
|
||||
msg = "the tag %s points to %s you cannot change the source using this module." % (tag, final_tag)
|
||||
msg = (
|
||||
"the tag %s points to %s you cannot change the source using this module."
|
||||
% (tag, final_tag)
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
|
||||
# Set the target item to import
|
||||
@@ -309,13 +330,13 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
name=ref.get("name"),
|
||||
namespace=self.params.get("namespace")
|
||||
namespace=self.params.get("namespace"),
|
||||
)
|
||||
result = self.kubernetes_facts(**params)
|
||||
if not result["api_found"]:
|
||||
msg = 'Failed to find API for resource with apiVersion "{0}" and kind "{1}"'.format(
|
||||
api_version, kind
|
||||
),
|
||||
)
|
||||
self.fail_json(msg=msg)
|
||||
imagestream = None
|
||||
if len(result["resources"]) > 0:
|
||||
@@ -335,7 +356,9 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
def parse_image_reference(self, image_ref):
|
||||
result, err = parse_docker_image_ref(image_ref, self.module)
|
||||
if result.get("digest"):
|
||||
self.fail_json(msg="Cannot import by ID, error with definition: %s" % image_ref)
|
||||
self.fail_json(
|
||||
msg="Cannot import by ID, error with definition: %s" % image_ref
|
||||
)
|
||||
tag = result.get("tag") or None
|
||||
if not self.params.get("all") and not tag:
|
||||
tag = "latest"
|
||||
@@ -345,7 +368,6 @@ class OpenShiftImportImage(AnsibleOpenshiftModule):
|
||||
return dict(name=result.get("name"), tag=tag, source=image_ref)
|
||||
|
||||
def execute_module(self):
|
||||
|
||||
names = []
|
||||
name = self.params.get("name")
|
||||
if isinstance(name, string_types):
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
@@ -24,109 +25,119 @@ LDAP_SEARCH_OUT_OF_SCOPE_ERROR = "trying to search by DN for an entry that exist
|
||||
|
||||
def validate_ldap_sync_config(config):
|
||||
# Validate url
|
||||
url = config.get('url')
|
||||
url = config.get("url")
|
||||
if not url:
|
||||
return "url should be non empty attribute."
|
||||
|
||||
# Make sure bindDN and bindPassword are both set, or both unset
|
||||
bind_dn = config.get('bindDN', "")
|
||||
bind_password = config.get('bindPassword', "")
|
||||
bind_dn = config.get("bindDN", "")
|
||||
bind_password = config.get("bindPassword", "")
|
||||
if (len(bind_dn) == 0) != (len(bind_password) == 0):
|
||||
return "bindDN and bindPassword must both be specified, or both be empty."
|
||||
|
||||
insecure = boolean(config.get('insecure'))
|
||||
ca_file = config.get('ca')
|
||||
insecure = boolean(config.get("insecure"))
|
||||
ca_file = config.get("ca")
|
||||
if insecure:
|
||||
if url.startswith('ldaps://'):
|
||||
if url.startswith("ldaps://"):
|
||||
return "Cannot use ldaps scheme with insecure=true."
|
||||
if ca_file:
|
||||
return "Cannot specify a ca with insecure=true."
|
||||
elif ca_file and not os.path.isfile(ca_file):
|
||||
return "could not read ca file: {0}.".format(ca_file)
|
||||
|
||||
nameMapping = config.get('groupUIDNameMapping', {})
|
||||
nameMapping = config.get("groupUIDNameMapping", {})
|
||||
for k, v in iteritems(nameMapping):
|
||||
if len(k) == 0 or len(v) == 0:
|
||||
return "groupUIDNameMapping has empty key or value"
|
||||
|
||||
schemas = []
|
||||
schema_list = ('rfc2307', 'activeDirectory', 'augmentedActiveDirectory')
|
||||
schema_list = ("rfc2307", "activeDirectory", "augmentedActiveDirectory")
|
||||
for schema in schema_list:
|
||||
if schema in config:
|
||||
schemas.append(schema)
|
||||
|
||||
if len(schemas) == 0:
|
||||
return "No schema-specific config was provided, should be one of %s" % ", ".join(schema_list)
|
||||
return (
|
||||
"No schema-specific config was provided, should be one of %s"
|
||||
% ", ".join(schema_list)
|
||||
)
|
||||
if len(schemas) > 1:
|
||||
return "Exactly one schema-specific config is required; found (%d) %s" % (len(schemas), ','.join(schemas))
|
||||
return "Exactly one schema-specific config is required; found (%d) %s" % (
|
||||
len(schemas),
|
||||
",".join(schemas),
|
||||
)
|
||||
|
||||
if schemas[0] == 'rfc2307':
|
||||
if schemas[0] == "rfc2307":
|
||||
return validate_RFC2307(config.get("rfc2307"))
|
||||
elif schemas[0] == 'activeDirectory':
|
||||
elif schemas[0] == "activeDirectory":
|
||||
return validate_ActiveDirectory(config.get("activeDirectory"))
|
||||
elif schemas[0] == 'augmentedActiveDirectory':
|
||||
elif schemas[0] == "augmentedActiveDirectory":
|
||||
return validate_AugmentedActiveDirectory(config.get("augmentedActiveDirectory"))
|
||||
|
||||
|
||||
def validate_ldap_query(qry, isDNOnly=False):
|
||||
|
||||
# validate query scope
|
||||
scope = qry.get('scope')
|
||||
scope = qry.get("scope")
|
||||
if scope and scope not in ("", "sub", "one", "base"):
|
||||
return "invalid scope %s" % scope
|
||||
|
||||
# validate deref aliases
|
||||
derefAlias = qry.get('derefAliases')
|
||||
derefAlias = qry.get("derefAliases")
|
||||
if derefAlias and derefAlias not in ("never", "search", "base", "always"):
|
||||
return "not a valid LDAP alias dereferncing behavior: %s", derefAlias
|
||||
|
||||
# validate timeout
|
||||
timeout = qry.get('timeout')
|
||||
timeout = qry.get("timeout")
|
||||
if timeout and float(timeout) < 0:
|
||||
return "timeout must be equal to or greater than zero"
|
||||
|
||||
# Validate DN only
|
||||
qry_filter = qry.get('filter', "")
|
||||
qry_filter = qry.get("filter", "")
|
||||
if isDNOnly:
|
||||
if len(qry_filter) > 0:
|
||||
return 'cannot specify a filter when using "dn" as the UID attribute'
|
||||
else:
|
||||
# validate filter
|
||||
if len(qry_filter) == 0 or qry_filter[0] != '(':
|
||||
if len(qry_filter) == 0 or qry_filter[0] != "(":
|
||||
return "filter does not start with an '('"
|
||||
return None
|
||||
|
||||
|
||||
def validate_RFC2307(config):
|
||||
qry = config.get('groupsQuery')
|
||||
qry = config.get("groupsQuery")
|
||||
if not qry or not isinstance(qry, dict):
|
||||
return "RFC2307: groupsQuery requires a dictionary"
|
||||
error = validate_ldap_query(qry)
|
||||
if not error:
|
||||
return error
|
||||
for field in ('groupUIDAttribute', 'groupNameAttributes', 'groupMembershipAttributes',
|
||||
'userUIDAttribute', 'userNameAttributes'):
|
||||
for field in (
|
||||
"groupUIDAttribute",
|
||||
"groupNameAttributes",
|
||||
"groupMembershipAttributes",
|
||||
"userUIDAttribute",
|
||||
"userNameAttributes",
|
||||
):
|
||||
value = config.get(field)
|
||||
if not value:
|
||||
return "RFC2307: {0} is required.".format(field)
|
||||
|
||||
users_qry = config.get('usersQuery')
|
||||
users_qry = config.get("usersQuery")
|
||||
if not users_qry or not isinstance(users_qry, dict):
|
||||
return "RFC2307: usersQuery requires a dictionary"
|
||||
|
||||
isUserDNOnly = (config.get('userUIDAttribute').strip() == 'dn')
|
||||
isUserDNOnly = config.get("userUIDAttribute").strip() == "dn"
|
||||
return validate_ldap_query(users_qry, isDNOnly=isUserDNOnly)
|
||||
|
||||
|
||||
def validate_ActiveDirectory(config, label="ActiveDirectory"):
|
||||
users_qry = config.get('usersQuery')
|
||||
users_qry = config.get("usersQuery")
|
||||
if not users_qry or not isinstance(users_qry, dict):
|
||||
return "{0}: usersQuery requires as dictionnary".format(label)
|
||||
error = validate_ldap_query(users_qry)
|
||||
if not error:
|
||||
return error
|
||||
|
||||
for field in ('userNameAttributes', 'groupMembershipAttributes'):
|
||||
for field in ("userNameAttributes", "groupMembershipAttributes"):
|
||||
value = config.get(field)
|
||||
if not value:
|
||||
return "{0}: {1} is required.".format(field, label)
|
||||
@@ -138,24 +149,24 @@ def validate_AugmentedActiveDirectory(config):
|
||||
error = validate_ActiveDirectory(config, label="AugmentedActiveDirectory")
|
||||
if not error:
|
||||
return error
|
||||
for field in ('groupUIDAttribute', 'groupNameAttributes'):
|
||||
for field in ("groupUIDAttribute", "groupNameAttributes"):
|
||||
value = config.get(field)
|
||||
if not value:
|
||||
return "AugmentedActiveDirectory: {0} is required".format(field)
|
||||
groups_qry = config.get('groupsQuery')
|
||||
groups_qry = config.get("groupsQuery")
|
||||
if not groups_qry or not isinstance(groups_qry, dict):
|
||||
return "AugmentedActiveDirectory: groupsQuery requires as dictionnary."
|
||||
|
||||
isGroupDNOnly = (config.get('groupUIDAttribute').strip() == 'dn')
|
||||
isGroupDNOnly = config.get("groupUIDAttribute").strip() == "dn"
|
||||
return validate_ldap_query(groups_qry, isDNOnly=isGroupDNOnly)
|
||||
|
||||
|
||||
def determine_ldap_scope(scope):
|
||||
if scope in ("", "sub"):
|
||||
return ldap.SCOPE_SUBTREE
|
||||
elif scope == 'base':
|
||||
elif scope == "base":
|
||||
return ldap.SCOPE_BASE
|
||||
elif scope == 'one':
|
||||
elif scope == "one":
|
||||
return ldap.SCOPE_ONELEVEL
|
||||
return None
|
||||
|
||||
@@ -175,28 +186,28 @@ def determine_deref_aliases(derefAlias):
|
||||
|
||||
def openshift_ldap_build_base_query(config):
|
||||
qry = {}
|
||||
if config.get('baseDN'):
|
||||
qry['base'] = config.get('baseDN')
|
||||
if config.get("baseDN"):
|
||||
qry["base"] = config.get("baseDN")
|
||||
|
||||
scope = determine_ldap_scope(config.get('scope'))
|
||||
scope = determine_ldap_scope(config.get("scope"))
|
||||
if scope:
|
||||
qry['scope'] = scope
|
||||
qry["scope"] = scope
|
||||
|
||||
pageSize = config.get('pageSize')
|
||||
pageSize = config.get("pageSize")
|
||||
if pageSize and int(pageSize) > 0:
|
||||
qry['sizelimit'] = int(pageSize)
|
||||
qry["sizelimit"] = int(pageSize)
|
||||
|
||||
timeout = config.get('timeout')
|
||||
timeout = config.get("timeout")
|
||||
if timeout and int(timeout) > 0:
|
||||
qry['timeout'] = int(timeout)
|
||||
qry["timeout"] = int(timeout)
|
||||
|
||||
filter = config.get('filter')
|
||||
filter = config.get("filter")
|
||||
if filter:
|
||||
qry['filterstr'] = filter
|
||||
qry["filterstr"] = filter
|
||||
|
||||
derefAlias = determine_deref_aliases(config.get('derefAliases'))
|
||||
derefAlias = determine_deref_aliases(config.get("derefAliases"))
|
||||
if derefAlias:
|
||||
qry['derefAlias'] = derefAlias
|
||||
qry["derefAlias"] = derefAlias
|
||||
return qry
|
||||
|
||||
|
||||
@@ -205,32 +216,30 @@ def openshift_ldap_get_attribute_for_entry(entry, attribute):
|
||||
if isinstance(attribute, list):
|
||||
attributes = attribute
|
||||
for k in attributes:
|
||||
if k.lower() == 'dn':
|
||||
if k.lower() == "dn":
|
||||
return entry[0]
|
||||
v = entry[1].get(k, None)
|
||||
if v:
|
||||
if isinstance(v, list):
|
||||
result = []
|
||||
for x in v:
|
||||
if hasattr(x, 'decode'):
|
||||
result.append(x.decode('utf-8'))
|
||||
if hasattr(x, "decode"):
|
||||
result.append(x.decode("utf-8"))
|
||||
else:
|
||||
result.append(x)
|
||||
return result
|
||||
else:
|
||||
return v.decode('utf-8') if hasattr(v, 'decode') else v
|
||||
return v.decode("utf-8") if hasattr(v, "decode") else v
|
||||
return ""
|
||||
|
||||
|
||||
def ldap_split_host_port(hostport):
|
||||
"""
|
||||
ldap_split_host_port splits a network address of the form "host:port",
|
||||
"host%zone:port", "[host]:port" or "[host%zone]:port" into host or
|
||||
host%zone and port.
|
||||
ldap_split_host_port splits a network address of the form "host:port",
|
||||
"host%zone:port", "[host]:port" or "[host%zone]:port" into host or
|
||||
host%zone and port.
|
||||
"""
|
||||
result = dict(
|
||||
scheme=None, netlocation=None, host=None, port=None
|
||||
)
|
||||
result = dict(scheme=None, netlocation=None, host=None, port=None)
|
||||
if not hostport:
|
||||
return result, None
|
||||
|
||||
@@ -240,10 +249,10 @@ def ldap_split_host_port(hostport):
|
||||
if "://" in hostport:
|
||||
idx = hostport.find(scheme_l)
|
||||
result["scheme"] = hostport[:idx]
|
||||
netlocation = hostport[idx + len(scheme_l):]
|
||||
netlocation = hostport[idx + len(scheme_l):] # fmt: skip
|
||||
result["netlocation"] = netlocation
|
||||
|
||||
if netlocation[-1] == ']':
|
||||
if netlocation[-1] == "]":
|
||||
# ipv6 literal (with no port)
|
||||
result["host"] = netlocation
|
||||
|
||||
@@ -259,21 +268,32 @@ def ldap_split_host_port(hostport):
|
||||
|
||||
def openshift_ldap_query_for_entries(connection, qry, unique_entry=True):
|
||||
# set deref alias (TODO: need to set a default value to reset for each transaction)
|
||||
derefAlias = qry.pop('derefAlias', None)
|
||||
derefAlias = qry.pop("derefAlias", None)
|
||||
if derefAlias:
|
||||
ldap.set_option(ldap.OPT_DEREF, derefAlias)
|
||||
try:
|
||||
result = connection.search_ext_s(**qry)
|
||||
if not result or len(result) == 0:
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(qry['base'], qry['filterstr'])
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(
|
||||
qry["base"], qry["filterstr"]
|
||||
)
|
||||
if len(result) > 1 and unique_entry:
|
||||
if qry.get('scope') == ldap.SCOPE_BASE:
|
||||
return None, "multiple entries found matching dn={0}: {1}".format(qry['base'], result)
|
||||
if qry.get("scope") == ldap.SCOPE_BASE:
|
||||
return None, "multiple entries found matching dn={0}: {1}".format(
|
||||
qry["base"], result
|
||||
)
|
||||
else:
|
||||
return None, "multiple entries found matching filter {0}: {1}".format(qry['filterstr'], result)
|
||||
return None, "multiple entries found matching filter {0}: {1}".format(
|
||||
qry["filterstr"], result
|
||||
)
|
||||
return result, None
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
return None, "search for entry with base dn='{0}' refers to a non-existent entry".format(qry['base'])
|
||||
return (
|
||||
None,
|
||||
"search for entry with base dn='{0}' refers to a non-existent entry".format(
|
||||
qry["base"]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def openshift_equal_dn_objects(dn_obj, other_dn_obj):
|
||||
@@ -303,7 +323,9 @@ def openshift_ancestorof_dn(dn, other):
|
||||
if len(dn_obj) >= len(other_dn_obj):
|
||||
return False
|
||||
# Take the last attribute from the other DN to compare against
|
||||
return openshift_equal_dn_objects(dn_obj, other_dn_obj[len(other_dn_obj) - len(dn_obj):])
|
||||
return openshift_equal_dn_objects(
|
||||
dn_obj, other_dn_obj[len(other_dn_obj) - len(dn_obj):] # fmt: skip
|
||||
)
|
||||
|
||||
|
||||
class OpenshiftLDAPQueryOnAttribute(object):
|
||||
@@ -324,33 +346,38 @@ class OpenshiftLDAPQueryOnAttribute(object):
|
||||
output = []
|
||||
hex_string = "0123456789abcdef"
|
||||
for c in buffer:
|
||||
if ord(c) > 0x7f or c in ('(', ')', '\\', '*') or c == 0:
|
||||
if ord(c) > 0x7F or c in ("(", ")", "\\", "*") or c == 0:
|
||||
first = ord(c) >> 4
|
||||
second = ord(c) & 0xf
|
||||
output += ['\\', hex_string[first], hex_string[second]]
|
||||
second = ord(c) & 0xF
|
||||
output += ["\\", hex_string[first], hex_string[second]]
|
||||
else:
|
||||
output.append(c)
|
||||
return ''.join(output)
|
||||
return "".join(output)
|
||||
|
||||
def build_request(self, ldapuid, attributes):
|
||||
params = copy.deepcopy(self.qry)
|
||||
if self.query_attribute.lower() == 'dn':
|
||||
if self.query_attribute.lower() == "dn":
|
||||
if ldapuid:
|
||||
if not openshift_equal_dn(ldapuid, params['base']) and not openshift_ancestorof_dn(params['base'], ldapuid):
|
||||
if not openshift_equal_dn(
|
||||
ldapuid, params["base"]
|
||||
) and not openshift_ancestorof_dn(params["base"], ldapuid):
|
||||
return None, LDAP_SEARCH_OUT_OF_SCOPE_ERROR
|
||||
params['base'] = ldapuid
|
||||
params['scope'] = ldap.SCOPE_BASE
|
||||
params["base"] = ldapuid
|
||||
params["scope"] = ldap.SCOPE_BASE
|
||||
# filter that returns all values
|
||||
params['filterstr'] = "(objectClass=*)"
|
||||
params['attrlist'] = attributes
|
||||
params["filterstr"] = "(objectClass=*)"
|
||||
params["attrlist"] = attributes
|
||||
else:
|
||||
# Builds the query containing a filter that conjoins the common filter given
|
||||
# in the configuration with the specific attribute filter for which the attribute value is given
|
||||
specificFilter = "%s=%s" % (self.escape_filter(self.query_attribute), self.escape_filter(ldapuid))
|
||||
qry_filter = params.get('filterstr', None)
|
||||
specificFilter = "%s=%s" % (
|
||||
self.escape_filter(self.query_attribute),
|
||||
self.escape_filter(ldapuid),
|
||||
)
|
||||
qry_filter = params.get("filterstr", None)
|
||||
if qry_filter:
|
||||
params['filterstr'] = "(&%s(%s))" % (qry_filter, specificFilter)
|
||||
params['attrlist'] = attributes
|
||||
params["filterstr"] = "(&%s(%s))" % (qry_filter, specificFilter)
|
||||
params["attrlist"] = attributes
|
||||
return params, None
|
||||
|
||||
def ldap_search(self, connection, ldapuid, required_attributes, unique_entry=True):
|
||||
@@ -358,21 +385,29 @@ class OpenshiftLDAPQueryOnAttribute(object):
|
||||
if error:
|
||||
return None, error
|
||||
# set deref alias (TODO: need to set a default value to reset for each transaction)
|
||||
derefAlias = query.pop('derefAlias', None)
|
||||
derefAlias = query.pop("derefAlias", None)
|
||||
if derefAlias:
|
||||
ldap.set_option(ldap.OPT_DEREF, derefAlias)
|
||||
|
||||
try:
|
||||
result = connection.search_ext_s(**query)
|
||||
if not result or len(result) == 0:
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(query['base'], query['filterstr'])
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(
|
||||
query["base"], query["filterstr"]
|
||||
)
|
||||
if unique_entry:
|
||||
if len(result) > 1:
|
||||
return None, "Multiple Entries found matching search criteria: %s (%s)" % (query, result)
|
||||
return (
|
||||
None,
|
||||
"Multiple Entries found matching search criteria: %s (%s)"
|
||||
% (query, result),
|
||||
)
|
||||
result = result[0]
|
||||
return result, None
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(query['base'], query['filterstr'])
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(
|
||||
query["base"], query["filterstr"]
|
||||
)
|
||||
except Exception as err:
|
||||
return None, "Request %s failed due to: %s" % (query, err)
|
||||
|
||||
@@ -384,30 +419,43 @@ class OpenshiftLDAPQuery(object):
|
||||
|
||||
def build_request(self, attributes):
|
||||
params = copy.deepcopy(self.qry)
|
||||
params['attrlist'] = attributes
|
||||
params["attrlist"] = attributes
|
||||
return params
|
||||
|
||||
def ldap_search(self, connection, required_attributes):
|
||||
query = self.build_request(required_attributes)
|
||||
# set deref alias (TODO: need to set a default value to reset for each transaction)
|
||||
derefAlias = query.pop('derefAlias', None)
|
||||
derefAlias = query.pop("derefAlias", None)
|
||||
if derefAlias:
|
||||
ldap.set_option(ldap.OPT_DEREF, derefAlias)
|
||||
|
||||
try:
|
||||
result = connection.search_ext_s(**query)
|
||||
if not result or len(result) == 0:
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(query['base'], query['filterstr'])
|
||||
return None, "Entry not found for base='{0}' and filter='{1}'".format(
|
||||
query["base"], query["filterstr"]
|
||||
)
|
||||
return result, None
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
return None, "search for entry with base dn='{0}' refers to a non-existent entry".format(query['base'])
|
||||
return (
|
||||
None,
|
||||
"search for entry with base dn='{0}' refers to a non-existent entry".format(
|
||||
query["base"]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class OpenshiftLDAPInterface(object):
|
||||
|
||||
def __init__(self, connection, groupQuery, groupNameAttributes, groupMembershipAttributes,
|
||||
userQuery, userNameAttributes, config):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
connection,
|
||||
groupQuery,
|
||||
groupNameAttributes,
|
||||
groupMembershipAttributes,
|
||||
userQuery,
|
||||
userNameAttributes,
|
||||
config,
|
||||
):
|
||||
self.connection = connection
|
||||
self.groupQuery = copy.deepcopy(groupQuery)
|
||||
self.groupNameAttributes = groupNameAttributes
|
||||
@@ -416,8 +464,12 @@ class OpenshiftLDAPInterface(object):
|
||||
self.userNameAttributes = userNameAttributes
|
||||
self.config = config
|
||||
|
||||
self.tolerate_not_found = boolean(config.get('tolerateMemberNotFoundErrors', False))
|
||||
self.tolerate_out_of_scope = boolean(config.get('tolerateMemberOutOfScopeErrors', False))
|
||||
self.tolerate_not_found = boolean(
|
||||
config.get("tolerateMemberNotFoundErrors", False)
|
||||
)
|
||||
self.tolerate_out_of_scope = boolean(
|
||||
config.get("tolerateMemberOutOfScopeErrors", False)
|
||||
)
|
||||
|
||||
self.required_group_attributes = [self.groupQuery.query_attribute]
|
||||
for x in self.groupNameAttributes + self.groupMembershipAttributes:
|
||||
@@ -434,13 +486,15 @@ class OpenshiftLDAPInterface(object):
|
||||
|
||||
def get_group_entry(self, uid):
|
||||
"""
|
||||
get_group_entry returns an LDAP group entry for the given group UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
get_group_entry returns an LDAP group entry for the given group UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
"""
|
||||
if uid in self.cached_groups:
|
||||
return self.cached_groups.get(uid), None
|
||||
|
||||
group, err = self.groupQuery.ldap_search(self.connection, uid, self.required_group_attributes)
|
||||
group, err = self.groupQuery.ldap_search(
|
||||
self.connection, uid, self.required_group_attributes
|
||||
)
|
||||
if err:
|
||||
return None, err
|
||||
self.cached_groups[uid] = group
|
||||
@@ -448,13 +502,15 @@ class OpenshiftLDAPInterface(object):
|
||||
|
||||
def get_user_entry(self, uid):
|
||||
"""
|
||||
get_user_entry returns an LDAP group entry for the given user UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
get_user_entry returns an LDAP group entry for the given user UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
"""
|
||||
if uid in self.cached_users:
|
||||
return self.cached_users.get(uid), None
|
||||
|
||||
entry, err = self.userQuery.ldap_search(self.connection, uid, self.required_user_attributes)
|
||||
entry, err = self.userQuery.ldap_search(
|
||||
self.connection, uid, self.required_user_attributes
|
||||
)
|
||||
if err:
|
||||
return None, err
|
||||
self.cached_users[uid] = entry
|
||||
@@ -466,19 +522,19 @@ class OpenshiftLDAPInterface(object):
|
||||
|
||||
def list_groups(self):
|
||||
group_qry = copy.deepcopy(self.groupQuery.qry)
|
||||
group_qry['attrlist'] = self.required_group_attributes
|
||||
group_qry["attrlist"] = self.required_group_attributes
|
||||
|
||||
groups, err = openshift_ldap_query_for_entries(
|
||||
connection=self.connection,
|
||||
qry=group_qry,
|
||||
unique_entry=False
|
||||
connection=self.connection, qry=group_qry, unique_entry=False
|
||||
)
|
||||
if err:
|
||||
return None, err
|
||||
|
||||
group_uids = []
|
||||
for entry in groups:
|
||||
uid = openshift_ldap_get_attribute_for_entry(entry, self.groupQuery.query_attribute)
|
||||
uid = openshift_ldap_get_attribute_for_entry(
|
||||
entry, self.groupQuery.query_attribute
|
||||
)
|
||||
if not uid:
|
||||
return None, "Unable to find LDAP group uid for entry %s" % entry
|
||||
self.cached_groups[uid] = entry
|
||||
@@ -487,7 +543,7 @@ class OpenshiftLDAPInterface(object):
|
||||
|
||||
def extract_members(self, uid):
|
||||
"""
|
||||
returns the LDAP member entries for a group specified with a ldapGroupUID
|
||||
returns the LDAP member entries for a group specified with a ldapGroupUID
|
||||
"""
|
||||
# Get group entry from LDAP
|
||||
group, err = self.get_group_entry(uid)
|
||||
@@ -514,39 +570,46 @@ class OpenshiftLDAPInterface(object):
|
||||
|
||||
|
||||
class OpenshiftLDAPRFC2307(object):
|
||||
|
||||
def __init__(self, config, ldap_connection):
|
||||
|
||||
self.config = config
|
||||
self.ldap_interface = self.create_ldap_interface(ldap_connection)
|
||||
|
||||
def create_ldap_interface(self, connection):
|
||||
segment = self.config.get("rfc2307")
|
||||
groups_base_qry = openshift_ldap_build_base_query(segment['groupsQuery'])
|
||||
users_base_qry = openshift_ldap_build_base_query(segment['usersQuery'])
|
||||
groups_base_qry = openshift_ldap_build_base_query(segment["groupsQuery"])
|
||||
users_base_qry = openshift_ldap_build_base_query(segment["usersQuery"])
|
||||
|
||||
groups_query = OpenshiftLDAPQueryOnAttribute(groups_base_qry, segment['groupUIDAttribute'])
|
||||
users_query = OpenshiftLDAPQueryOnAttribute(users_base_qry, segment['userUIDAttribute'])
|
||||
groups_query = OpenshiftLDAPQueryOnAttribute(
|
||||
groups_base_qry, segment["groupUIDAttribute"]
|
||||
)
|
||||
users_query = OpenshiftLDAPQueryOnAttribute(
|
||||
users_base_qry, segment["userUIDAttribute"]
|
||||
)
|
||||
|
||||
params = dict(
|
||||
connection=connection,
|
||||
groupQuery=groups_query,
|
||||
groupNameAttributes=segment['groupNameAttributes'],
|
||||
groupMembershipAttributes=segment['groupMembershipAttributes'],
|
||||
groupNameAttributes=segment["groupNameAttributes"],
|
||||
groupMembershipAttributes=segment["groupMembershipAttributes"],
|
||||
userQuery=users_query,
|
||||
userNameAttributes=segment['userNameAttributes'],
|
||||
config=segment
|
||||
userNameAttributes=segment["userNameAttributes"],
|
||||
config=segment,
|
||||
)
|
||||
return OpenshiftLDAPInterface(**params)
|
||||
|
||||
def get_username_for_entry(self, entry):
|
||||
username = openshift_ldap_get_attribute_for_entry(entry, self.ldap_interface.userNameAttributes)
|
||||
username = openshift_ldap_get_attribute_for_entry(
|
||||
entry, self.ldap_interface.userNameAttributes
|
||||
)
|
||||
if not username:
|
||||
return None, "The user entry (%s) does not map to a OpenShift User name with the given mapping" % entry
|
||||
return (
|
||||
None,
|
||||
"The user entry (%s) does not map to a OpenShift User name with the given mapping"
|
||||
% entry,
|
||||
)
|
||||
return username, None
|
||||
|
||||
def get_group_name_for_uid(self, uid):
|
||||
|
||||
# Get name from User defined mapping
|
||||
groupuid_name_mapping = self.config.get("groupUIDNameMapping")
|
||||
if groupuid_name_mapping and uid in groupuid_name_mapping:
|
||||
@@ -555,10 +618,13 @@ class OpenshiftLDAPRFC2307(object):
|
||||
group, err = self.ldap_interface.get_group_entry(uid)
|
||||
if err:
|
||||
return None, err
|
||||
group_name = openshift_ldap_get_attribute_for_entry(group, self.ldap_interface.groupNameAttributes)
|
||||
group_name = openshift_ldap_get_attribute_for_entry(
|
||||
group, self.ldap_interface.groupNameAttributes
|
||||
)
|
||||
if not group_name:
|
||||
error = "The group entry (%s) does not map to an OpenShift Group name with the given name attribute (%s)" % (
|
||||
group, self.ldap_interface.groupNameAttributes
|
||||
error = (
|
||||
"The group entry (%s) does not map to an OpenShift Group name with the given name attribute (%s)"
|
||||
% (group, self.ldap_interface.groupNameAttributes)
|
||||
)
|
||||
return None, error
|
||||
if isinstance(group_name, list):
|
||||
@@ -570,7 +636,11 @@ class OpenshiftLDAPRFC2307(object):
|
||||
def is_ldapgroup_exists(self, uid):
|
||||
group, err = self.ldap_interface.get_group_entry(uid)
|
||||
if err:
|
||||
if err == LDAP_SEARCH_OUT_OF_SCOPE_ERROR or err.startswith("Entry not found") or "non-existent entry" in err:
|
||||
if (
|
||||
err == LDAP_SEARCH_OUT_OF_SCOPE_ERROR
|
||||
or err.startswith("Entry not found")
|
||||
or "non-existent entry" in err
|
||||
):
|
||||
return False, None
|
||||
return False, err
|
||||
if group:
|
||||
@@ -585,7 +655,6 @@ class OpenshiftLDAPRFC2307(object):
|
||||
|
||||
|
||||
class OpenshiftLDAP_ADInterface(object):
|
||||
|
||||
def __init__(self, connection, user_query, group_member_attr, user_name_attr):
|
||||
self.connection = connection
|
||||
self.userQuery = user_query
|
||||
@@ -609,7 +678,9 @@ class OpenshiftLDAP_ADInterface(object):
|
||||
def populate_cache(self):
|
||||
if not self.cache_populated:
|
||||
self.cache_populated = True
|
||||
entries, err = self.userQuery.ldap_search(self.connection, self.required_user_attributes)
|
||||
entries, err = self.userQuery.ldap_search(
|
||||
self.connection, self.required_user_attributes
|
||||
)
|
||||
if err:
|
||||
return err
|
||||
|
||||
@@ -645,7 +716,9 @@ class OpenshiftLDAP_ADInterface(object):
|
||||
users_in_group = []
|
||||
for attr in self.groupMembershipAttributes:
|
||||
query_on_attribute = OpenshiftLDAPQueryOnAttribute(self.userQuery.qry, attr)
|
||||
entries, error = query_on_attribute.ldap_search(self.connection, uid, self.required_user_attributes, unique_entry=False)
|
||||
entries, error = query_on_attribute.ldap_search(
|
||||
self.connection, uid, self.required_user_attributes, unique_entry=False
|
||||
)
|
||||
if error and "not found" not in error:
|
||||
return None, error
|
||||
if not entries:
|
||||
@@ -660,15 +733,13 @@ class OpenshiftLDAP_ADInterface(object):
|
||||
|
||||
|
||||
class OpenshiftLDAPActiveDirectory(object):
|
||||
|
||||
def __init__(self, config, ldap_connection):
|
||||
|
||||
self.config = config
|
||||
self.ldap_interface = self.create_ldap_interface(ldap_connection)
|
||||
|
||||
def create_ldap_interface(self, connection):
|
||||
segment = self.config.get("activeDirectory")
|
||||
base_query = openshift_ldap_build_base_query(segment['usersQuery'])
|
||||
base_query = openshift_ldap_build_base_query(segment["usersQuery"])
|
||||
user_query = OpenshiftLDAPQuery(base_query)
|
||||
|
||||
return OpenshiftLDAP_ADInterface(
|
||||
@@ -679,9 +750,15 @@ class OpenshiftLDAPActiveDirectory(object):
|
||||
)
|
||||
|
||||
def get_username_for_entry(self, entry):
|
||||
username = openshift_ldap_get_attribute_for_entry(entry, self.ldap_interface.userNameAttributes)
|
||||
username = openshift_ldap_get_attribute_for_entry(
|
||||
entry, self.ldap_interface.userNameAttributes
|
||||
)
|
||||
if not username:
|
||||
return None, "The user entry (%s) does not map to a OpenShift User name with the given mapping" % entry
|
||||
return (
|
||||
None,
|
||||
"The user entry (%s) does not map to a OpenShift User name with the given mapping"
|
||||
% entry,
|
||||
)
|
||||
return username, None
|
||||
|
||||
def get_group_name_for_uid(self, uid):
|
||||
@@ -702,8 +779,15 @@ class OpenshiftLDAPActiveDirectory(object):
|
||||
|
||||
|
||||
class OpenshiftLDAP_AugmentedADInterface(OpenshiftLDAP_ADInterface):
|
||||
|
||||
def __init__(self, connection, user_query, group_member_attr, user_name_attr, group_qry, group_name_attr):
|
||||
def __init__(
|
||||
self,
|
||||
connection,
|
||||
user_query,
|
||||
group_member_attr,
|
||||
user_name_attr,
|
||||
group_qry,
|
||||
group_name_attr,
|
||||
):
|
||||
super(OpenshiftLDAP_AugmentedADInterface, self).__init__(
|
||||
connection, user_query, group_member_attr, user_name_attr
|
||||
)
|
||||
@@ -719,13 +803,15 @@ class OpenshiftLDAP_AugmentedADInterface(OpenshiftLDAP_ADInterface):
|
||||
|
||||
def get_group_entry(self, uid):
|
||||
"""
|
||||
get_group_entry returns an LDAP group entry for the given group UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
get_group_entry returns an LDAP group entry for the given group UID by searching the internal cache
|
||||
of the LDAPInterface first, then sending an LDAP query if the cache did not contain the entry.
|
||||
"""
|
||||
if uid in self.cached_groups:
|
||||
return self.cached_groups.get(uid), None
|
||||
|
||||
group, err = self.groupQuery.ldap_search(self.connection, uid, self.required_group_attributes)
|
||||
group, err = self.groupQuery.ldap_search(
|
||||
self.connection, uid, self.required_group_attributes
|
||||
)
|
||||
if err:
|
||||
return None, err
|
||||
self.cached_groups[uid] = group
|
||||
@@ -750,19 +836,19 @@ class OpenshiftLDAP_AugmentedADInterface(OpenshiftLDAP_ADInterface):
|
||||
|
||||
|
||||
class OpenshiftLDAPAugmentedActiveDirectory(OpenshiftLDAPRFC2307):
|
||||
|
||||
def __init__(self, config, ldap_connection):
|
||||
|
||||
self.config = config
|
||||
self.ldap_interface = self.create_ldap_interface(ldap_connection)
|
||||
|
||||
def create_ldap_interface(self, connection):
|
||||
segment = self.config.get("augmentedActiveDirectory")
|
||||
user_base_query = openshift_ldap_build_base_query(segment['usersQuery'])
|
||||
groups_base_qry = openshift_ldap_build_base_query(segment['groupsQuery'])
|
||||
user_base_query = openshift_ldap_build_base_query(segment["usersQuery"])
|
||||
groups_base_qry = openshift_ldap_build_base_query(segment["groupsQuery"])
|
||||
|
||||
user_query = OpenshiftLDAPQuery(user_base_query)
|
||||
groups_query = OpenshiftLDAPQueryOnAttribute(groups_base_qry, segment['groupUIDAttribute'])
|
||||
groups_query = OpenshiftLDAPQueryOnAttribute(
|
||||
groups_base_qry, segment["groupUIDAttribute"]
|
||||
)
|
||||
|
||||
return OpenshiftLDAP_AugmentedADInterface(
|
||||
connection=connection,
|
||||
@@ -770,7 +856,7 @@ class OpenshiftLDAPAugmentedActiveDirectory(OpenshiftLDAPRFC2307):
|
||||
group_member_attr=segment["groupMembershipAttributes"],
|
||||
user_name_attr=segment["userNameAttributes"],
|
||||
group_qry=groups_query,
|
||||
group_name_attr=segment["groupNameAttributes"]
|
||||
group_name_attr=segment["groupNameAttributes"],
|
||||
)
|
||||
|
||||
def is_ldapgroup_exists(self, uid):
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -124,7 +125,6 @@ class OpenShiftProcess(AnsibleOpenshiftModule):
|
||||
self.exit_json(**result)
|
||||
|
||||
def create_resources(self, definitions):
|
||||
|
||||
params = {"namespace": self.params.get("namespace_target")}
|
||||
|
||||
self.params["apply"] = False
|
||||
@@ -139,9 +139,7 @@ class OpenShiftProcess(AnsibleOpenshiftModule):
|
||||
continue
|
||||
kind = definition.get("kind")
|
||||
if kind and kind.endswith("List"):
|
||||
flattened_definitions.extend(
|
||||
self.flatten_list_kind(definition, params)
|
||||
)
|
||||
flattened_definitions.extend(self.flatten_list_kind(definition, params))
|
||||
else:
|
||||
flattened_definitions.append(self.merge_params(definition, params))
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_docker_image import (
|
||||
parse_docker_image_ref,
|
||||
@@ -15,6 +18,7 @@ from ansible_collections.community.okd.plugins.module_utils.openshift_docker_ima
|
||||
try:
|
||||
from requests import request
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
HAS_REQUESTS_MODULE = True
|
||||
requests_import_exception = None
|
||||
except ImportError as e:
|
||||
@@ -32,11 +36,7 @@ class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
kind = "ImageStream"
|
||||
api_version = "image.openshift.io/v1"
|
||||
|
||||
params = dict(
|
||||
kind=kind,
|
||||
api_version=api_version,
|
||||
namespace=namespace
|
||||
)
|
||||
params = dict(kind=kind, api_version=api_version, namespace=namespace)
|
||||
result = self.kubernetes_facts(**params)
|
||||
imagestream = []
|
||||
if len(result["resources"]) > 0:
|
||||
@@ -44,7 +44,6 @@ class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
return imagestream
|
||||
|
||||
def find_registry_info(self):
|
||||
|
||||
def _determine_registry(image_stream):
|
||||
public, internal = None, None
|
||||
docker_repo = image_stream["status"].get("publicDockerImageRepository")
|
||||
@@ -72,39 +71,46 @@ class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
self.fail_json(msg="The integrated registry has not been configured")
|
||||
return internal, public
|
||||
|
||||
self.fail_json(msg="No Image Streams could be located to retrieve registry info.")
|
||||
self.fail_json(
|
||||
msg="No Image Streams could be located to retrieve registry info."
|
||||
)
|
||||
|
||||
def execute_module(self):
|
||||
result = {}
|
||||
result["internal_hostname"], result["public_hostname"] = self.find_registry_info()
|
||||
(
|
||||
result["internal_hostname"],
|
||||
result["public_hostname"],
|
||||
) = self.find_registry_info()
|
||||
|
||||
if self.check:
|
||||
public_registry = result["public_hostname"]
|
||||
if not public_registry:
|
||||
result["check"] = dict(
|
||||
reached=False,
|
||||
msg="Registry does not have a public hostname."
|
||||
reached=False, msg="Registry does not have a public hostname."
|
||||
)
|
||||
else:
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
params = {
|
||||
'method': 'GET',
|
||||
'verify': False
|
||||
}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
params = {"method": "GET", "verify": False}
|
||||
if self.client.configuration.api_key:
|
||||
headers.update(self.client.configuration.api_key)
|
||||
elif self.client.configuration.username and self.client.configuration.password:
|
||||
elif (
|
||||
self.client.configuration.username
|
||||
and self.client.configuration.password
|
||||
):
|
||||
if not HAS_REQUESTS_MODULE:
|
||||
result["check"] = dict(
|
||||
reached=False,
|
||||
msg="The requests python package is missing, try `pip install requests`",
|
||||
error=requests_import_exception
|
||||
error=requests_import_exception,
|
||||
)
|
||||
self.exit_json(**result)
|
||||
params.update(
|
||||
dict(auth=HTTPBasicAuth(self.client.configuration.username, self.client.configuration.password))
|
||||
dict(
|
||||
auth=HTTPBasicAuth(
|
||||
self.client.configuration.username,
|
||||
self.client.configuration.password,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# verify ssl
|
||||
@@ -112,23 +118,20 @@ class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
if len(host.scheme) == 0:
|
||||
registry_url = "https://" + public_registry
|
||||
|
||||
if registry_url.startswith("https://") and self.client.configuration.ssl_ca_cert:
|
||||
params.update(
|
||||
dict(verify=self.client.configuration.ssl_ca_cert)
|
||||
)
|
||||
params.update(
|
||||
dict(headers=headers)
|
||||
)
|
||||
if (
|
||||
registry_url.startswith("https://")
|
||||
and self.client.configuration.ssl_ca_cert
|
||||
):
|
||||
params.update(dict(verify=self.client.configuration.ssl_ca_cert))
|
||||
params.update(dict(headers=headers))
|
||||
last_bad_status, last_bad_reason = None, None
|
||||
for path in ("/", "/healthz"):
|
||||
params.update(
|
||||
dict(url=registry_url + path)
|
||||
)
|
||||
params.update(dict(url=registry_url + path))
|
||||
response = request(**params)
|
||||
if response.status_code == 200:
|
||||
result["check"] = dict(
|
||||
reached=True,
|
||||
msg="The local client can contact the integrated registry."
|
||||
msg="The local client can contact the integrated registry.",
|
||||
)
|
||||
self.exit_json(**result)
|
||||
last_bad_reason = response.reason
|
||||
@@ -136,9 +139,8 @@ class OpenShiftRegistry(AnsibleOpenshiftModule):
|
||||
|
||||
result["check"] = dict(
|
||||
reached=False,
|
||||
msg="Unable to contact the integrated registry using local client. Status=%d, Reason=%s" % (
|
||||
last_bad_status, last_bad_reason
|
||||
)
|
||||
msg="Unable to contact the integrated registry using local client. Status=%d, Reason=%s"
|
||||
% (last_bad_status, last_bad_reason),
|
||||
)
|
||||
|
||||
self.exit_json(**result)
|
||||
|
||||
@@ -10,7 +10,7 @@ from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: k8s
|
||||
|
||||
@@ -142,9 +142,9 @@ requirements:
|
||||
- "python >= 3.6"
|
||||
- "kubernetes >= 12.0.0"
|
||||
- "PyYAML >= 3.11"
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
- name: Create a k8s namespace
|
||||
community.okd.k8s:
|
||||
name: testing
|
||||
@@ -169,10 +169,10 @@ EXAMPLES = r'''
|
||||
app: galaxy
|
||||
service: web
|
||||
ports:
|
||||
- protocol: TCP
|
||||
targetPort: 8000
|
||||
name: port-8000-tcp
|
||||
port: 8000
|
||||
- protocol: TCP
|
||||
targetPort: 8000
|
||||
name: port-8000-tcp
|
||||
port: 8000
|
||||
|
||||
- name: Remove an existing Service object
|
||||
community.okd.k8s:
|
||||
@@ -206,18 +206,18 @@ EXAMPLES = r'''
|
||||
state: present
|
||||
definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}"
|
||||
validate:
|
||||
fail_on_error: yes
|
||||
fail_on_error: true
|
||||
|
||||
- name: warn on validation errors, check for unexpected properties
|
||||
community.okd.k8s:
|
||||
state: present
|
||||
definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}"
|
||||
validate:
|
||||
fail_on_error: no
|
||||
strict: yes
|
||||
'''
|
||||
fail_on_error: false
|
||||
strict: true
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
result:
|
||||
description:
|
||||
- The created, patched, or otherwise present object. Will be empty in the case of a deletion.
|
||||
@@ -254,22 +254,26 @@ result:
|
||||
type: int
|
||||
sample: 48
|
||||
error:
|
||||
description: error while trying to create/delete the object.
|
||||
description: Error while trying to create/delete the object.
|
||||
returned: error
|
||||
type: complex
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
NAME_ARG_SPEC, RESOURCE_ARG_SPEC, AUTH_ARG_SPEC, WAIT_ARG_SPEC, DELETE_OPTS_ARG_SPEC
|
||||
NAME_ARG_SPEC,
|
||||
RESOURCE_ARG_SPEC,
|
||||
AUTH_ARG_SPEC,
|
||||
WAIT_ARG_SPEC,
|
||||
DELETE_OPTS_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def validate_spec():
|
||||
return dict(
|
||||
fail_on_error=dict(type='bool'),
|
||||
fail_on_error=dict(type="bool"),
|
||||
version=dict(),
|
||||
strict=dict(type='bool', default=True)
|
||||
strict=dict(type="bool", default=True),
|
||||
)
|
||||
|
||||
|
||||
@@ -279,30 +283,41 @@ def argspec():
|
||||
argument_spec.update(RESOURCE_ARG_SPEC)
|
||||
argument_spec.update(AUTH_ARG_SPEC)
|
||||
argument_spec.update(WAIT_ARG_SPEC)
|
||||
argument_spec['merge_type'] = dict(type='list', elements='str', choices=['json', 'merge', 'strategic-merge'])
|
||||
argument_spec['validate'] = dict(type='dict', default=None, options=validate_spec())
|
||||
argument_spec['append_hash'] = dict(type='bool', default=False)
|
||||
argument_spec['apply'] = dict(type='bool', default=False)
|
||||
argument_spec['template'] = dict(type='raw', default=None)
|
||||
argument_spec['delete_options'] = dict(type='dict', default=None, options=DELETE_OPTS_ARG_SPEC)
|
||||
argument_spec['continue_on_error'] = dict(type='bool', default=False)
|
||||
argument_spec['state'] = dict(default='present', choices=['present', 'absent', 'patched'])
|
||||
argument_spec['force'] = dict(type='bool', default=False)
|
||||
argument_spec["merge_type"] = dict(
|
||||
type="list", elements="str", choices=["json", "merge", "strategic-merge"]
|
||||
)
|
||||
argument_spec["validate"] = dict(type="dict", default=None, options=validate_spec())
|
||||
argument_spec["append_hash"] = dict(type="bool", default=False)
|
||||
argument_spec["apply"] = dict(type="bool", default=False)
|
||||
argument_spec["template"] = dict(type="raw", default=None)
|
||||
argument_spec["delete_options"] = dict(
|
||||
type="dict", default=None, options=DELETE_OPTS_ARG_SPEC
|
||||
)
|
||||
argument_spec["continue_on_error"] = dict(type="bool", default=False)
|
||||
argument_spec["state"] = dict(
|
||||
default="present", choices=["present", "absent", "patched"]
|
||||
)
|
||||
argument_spec["force"] = dict(type="bool", default=False)
|
||||
return argument_spec
|
||||
|
||||
|
||||
def main():
|
||||
mutually_exclusive = [
|
||||
('resource_definition', 'src'),
|
||||
('merge_type', 'apply'),
|
||||
('template', 'resource_definition'),
|
||||
('template', 'src'),
|
||||
("resource_definition", "src"),
|
||||
("merge_type", "apply"),
|
||||
("template", "resource_definition"),
|
||||
("template", "src"),
|
||||
]
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.k8s import OKDRawModule
|
||||
module = OKDRawModule(argument_spec=argspec(), supports_check_mode=True, mutually_exclusive=mutually_exclusive)
|
||||
|
||||
module = OKDRawModule(
|
||||
argument_spec=argspec(),
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=mutually_exclusive,
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -96,31 +96,31 @@ EXAMPLES = r"""
|
||||
- name: Sync all groups from an LDAP server
|
||||
openshift_adm_groups_sync:
|
||||
src:
|
||||
kind: LDAPSyncConfig
|
||||
apiVersion: v1
|
||||
url: ldap://localhost:1390
|
||||
insecure: true
|
||||
bindDN: cn=admin,dc=example,dc=org
|
||||
bindPassword: adminpassword
|
||||
rfc2307:
|
||||
groupsQuery:
|
||||
baseDN: "cn=admins,ou=groups,dc=example,dc=org"
|
||||
scope: sub
|
||||
derefAliases: never
|
||||
filter: (objectClass=*)
|
||||
pageSize: 0
|
||||
groupUIDAttribute: dn
|
||||
groupNameAttributes: [ cn ]
|
||||
groupMembershipAttributes: [ member ]
|
||||
usersQuery:
|
||||
baseDN: "ou=users,dc=example,dc=org"
|
||||
scope: sub
|
||||
derefAliases: never
|
||||
pageSize: 0
|
||||
userUIDAttribute: dn
|
||||
userNameAttributes: [ mail ]
|
||||
tolerateMemberNotFoundErrors: true
|
||||
tolerateMemberOutOfScopeErrors: true
|
||||
kind: LDAPSyncConfig
|
||||
apiVersion: v1
|
||||
url: ldap://localhost:1390
|
||||
insecure: true
|
||||
bindDN: cn=admin,dc=example,dc=org
|
||||
bindPassword: adminpassword
|
||||
rfc2307:
|
||||
groupsQuery:
|
||||
baseDN: "cn=admins,ou=groups,dc=example,dc=org"
|
||||
scope: sub
|
||||
derefAliases: never
|
||||
filter: (objectClass=*)
|
||||
pageSize: 0
|
||||
groupUIDAttribute: dn
|
||||
groupNameAttributes: [cn]
|
||||
groupMembershipAttributes: [member]
|
||||
usersQuery:
|
||||
baseDN: "ou=users,dc=example,dc=org"
|
||||
scope: sub
|
||||
derefAliases: never
|
||||
pageSize: 0
|
||||
userUIDAttribute: dn
|
||||
userNameAttributes: [mail]
|
||||
tolerateMemberNotFoundErrors: true
|
||||
tolerateMemberOutOfScopeErrors: true
|
||||
|
||||
# Sync all groups except the ones from the deny_groups from an LDAP server
|
||||
- name: Sync all groups from an LDAP server using deny_groups
|
||||
@@ -192,20 +192,21 @@ builds:
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
import traceback
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
state=dict(type='str', choices=['absent', 'present'], default='present'),
|
||||
type=dict(type='str', choices=['ldap', 'openshift'], default='ldap'),
|
||||
sync_config=dict(type='dict', aliases=['config', 'src'], required=True),
|
||||
deny_groups=dict(type='list', elements='str', default=[]),
|
||||
allow_groups=dict(type='list', elements='str', default=[]),
|
||||
state=dict(type="str", choices=["absent", "present"], default="present"),
|
||||
type=dict(type="str", choices=["ldap", "openshift"], default="ldap"),
|
||||
sync_config=dict(type="dict", aliases=["config", "src"], required=True),
|
||||
deny_groups=dict(type="list", elements="str", default=[]),
|
||||
allow_groups=dict(type="list", elements="str", default=[]),
|
||||
)
|
||||
)
|
||||
return args
|
||||
@@ -213,12 +214,14 @@ def argument_spec():
|
||||
|
||||
def main():
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_groups import (
|
||||
OpenshiftGroupsSync
|
||||
OpenshiftGroupsSync,
|
||||
)
|
||||
|
||||
module = OpenshiftGroupsSync(argument_spec=argument_spec(), supports_check_mode=True)
|
||||
module = OpenshiftGroupsSync(
|
||||
argument_spec=argument_spec(), supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -31,14 +31,14 @@ requirements:
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Migrate TemplateInstances in namespace=test
|
||||
community.okd.openshift_adm_migrate_template_instances:
|
||||
namespace: test
|
||||
register: _result
|
||||
- name: Migrate TemplateInstances in namespace=test
|
||||
community.okd.openshift_adm_migrate_template_instances:
|
||||
namespace: test
|
||||
register: _result
|
||||
|
||||
- name: Migrate TemplateInstances in all namespaces
|
||||
community.okd.openshift_adm_migrate_template_instances:
|
||||
register: _result
|
||||
- name: Migrate TemplateInstances in all namespaces
|
||||
community.okd.openshift_adm_migrate_template_instances:
|
||||
register: _result
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
@@ -235,7 +235,9 @@ result:
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from kubernetes.dynamic.exceptions import DynamicApiError
|
||||
@@ -339,9 +341,7 @@ class OpenShiftMigrateTemplateInstances(AnsibleOpenshiftModule):
|
||||
|
||||
if ti_to_be_migrated:
|
||||
if self.check_mode:
|
||||
self.exit_json(
|
||||
**{"changed": True, "result": ti_to_be_migrated}
|
||||
)
|
||||
self.exit_json(**{"changed": True, "result": ti_to_be_migrated})
|
||||
else:
|
||||
for ti_elem in ti_to_be_migrated:
|
||||
results["result"].append(
|
||||
@@ -363,7 +363,9 @@ def argspec():
|
||||
|
||||
def main():
|
||||
argument_spec = argspec()
|
||||
module = OpenShiftMigrateTemplateInstances(argument_spec=argument_spec, supports_check_mode=True)
|
||||
module = OpenShiftMigrateTemplateInstances(
|
||||
argument_spec=argument_spec, supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_adm_prune_auth
|
||||
|
||||
@@ -58,9 +59,9 @@ options:
|
||||
requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
- name: Prune all roles from default namespace
|
||||
openshift_adm_prune_auth:
|
||||
resource: roles
|
||||
@@ -72,10 +73,10 @@ EXAMPLES = r'''
|
||||
namespace: testing
|
||||
label_selectors:
|
||||
- phase=production
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
cluster_role_binding:
|
||||
type: list
|
||||
description: list of cluster role binding deleted.
|
||||
@@ -96,37 +97,45 @@ group:
|
||||
type: list
|
||||
description: list of Security Context Constraints deleted.
|
||||
returned: I(resource=users)
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
resource=dict(type='str', required=True, choices=['roles', 'clusterroles', 'users', 'groups']),
|
||||
namespace=dict(type='str'),
|
||||
name=dict(type='str'),
|
||||
label_selectors=dict(type='list', elements='str'),
|
||||
resource=dict(
|
||||
type="str",
|
||||
required=True,
|
||||
choices=["roles", "clusterroles", "users", "groups"],
|
||||
),
|
||||
namespace=dict(type="str"),
|
||||
name=dict(type="str"),
|
||||
label_selectors=dict(type="list", elements="str"),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_auth import (
|
||||
OpenShiftAdmPruneAuth)
|
||||
OpenShiftAdmPruneAuth,
|
||||
)
|
||||
|
||||
module = OpenShiftAdmPruneAuth(argument_spec=argument_spec(),
|
||||
mutually_exclusive=[("name", "label_selectors")],
|
||||
supports_check_mode=True)
|
||||
module = OpenShiftAdmPruneAuth(
|
||||
argument_spec=argument_spec(),
|
||||
mutually_exclusive=[("name", "label_selectors")],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_adm_prune_builds
|
||||
|
||||
@@ -45,14 +46,14 @@ options:
|
||||
requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# Run deleting older completed and failed builds and also including
|
||||
# all builds whose associated BuildConfig no longer exists
|
||||
- name: Run delete orphan Builds
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
orphans: True
|
||||
orphans: true
|
||||
|
||||
# Run deleting older completed and failed builds keep younger than 2hours
|
||||
- name: Run delete builds, keep younger than 2h
|
||||
@@ -63,9 +64,9 @@ EXAMPLES = r'''
|
||||
- name: Run delete builds from namespace
|
||||
community.okd.openshift_adm_prune_builds:
|
||||
namespace: testing_namespace
|
||||
'''
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
builds:
|
||||
description:
|
||||
- The builds that were deleted
|
||||
@@ -92,33 +93,38 @@ builds:
|
||||
description: Current status details for the object.
|
||||
returned: success
|
||||
type: dict
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
namespace=dict(type='str'),
|
||||
keep_younger_than=dict(type='int'),
|
||||
orphans=dict(type='bool', default=False),
|
||||
namespace=dict(type="str"),
|
||||
keep_younger_than=dict(type="int"),
|
||||
orphans=dict(type="bool", default=False),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import (
|
||||
OpenShiftPruneBuilds,
|
||||
)
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import OpenShiftPruneBuilds
|
||||
|
||||
module = OpenShiftPruneBuilds(argument_spec=argument_spec(), supports_check_mode=True)
|
||||
module = OpenShiftPruneBuilds(
|
||||
argument_spec=argument_spec(), supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_adm_prune_deployments
|
||||
|
||||
@@ -45,32 +46,34 @@ options:
|
||||
requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
- name: Prune Deployments from testing namespace
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
namespace: testing
|
||||
|
||||
- name: Prune orphans deployments, keep younger than 2hours
|
||||
community.okd.openshift_adm_prune_deployments:
|
||||
orphans: True
|
||||
orphans: true
|
||||
keep_younger_than: 120
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
replication_controllers:
|
||||
type: list
|
||||
description: list of replication controllers candidate for pruning.
|
||||
returned: always
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
except ImportError as e:
|
||||
pass
|
||||
|
||||
@@ -79,22 +82,28 @@ def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
namespace=dict(type='str',),
|
||||
keep_younger_than=dict(type='int',),
|
||||
orphans=dict(type='bool', default=False),
|
||||
namespace=dict(
|
||||
type="str",
|
||||
),
|
||||
keep_younger_than=dict(
|
||||
type="int",
|
||||
),
|
||||
orphans=dict(type="bool", default=False),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_deployments import (
|
||||
OpenShiftAdmPruneDeployment)
|
||||
OpenShiftAdmPruneDeployment,
|
||||
)
|
||||
|
||||
module = OpenShiftAdmPruneDeployment(argument_spec=argument_spec(), supports_check_mode=True)
|
||||
module = OpenShiftAdmPruneDeployment(
|
||||
argument_spec=argument_spec(), supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_adm_prune_images
|
||||
|
||||
@@ -84,9 +85,9 @@ requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
- docker-image-py
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# Prune if only images and their referrers were more than an hour old
|
||||
- name: Prune image with referrer been more than an hour old
|
||||
community.okd.openshift_adm_prune_images:
|
||||
@@ -102,10 +103,10 @@ EXAMPLES = r'''
|
||||
community.okd.openshift_adm_prune_images:
|
||||
registry_url: http://registry.example.org
|
||||
registry_validate_certs: false
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
updated_image_streams:
|
||||
description:
|
||||
- The images streams updated.
|
||||
@@ -275,41 +276,44 @@ deleted_images:
|
||||
},
|
||||
...
|
||||
]
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
namespace=dict(type='str'),
|
||||
all_images=dict(type='bool', default=True),
|
||||
keep_younger_than=dict(type='int'),
|
||||
prune_over_size_limit=dict(type='bool', default=False),
|
||||
registry_url=dict(type='str'),
|
||||
registry_validate_certs=dict(type='bool'),
|
||||
registry_ca_cert=dict(type='path'),
|
||||
prune_registry=dict(type='bool', default=True),
|
||||
ignore_invalid_refs=dict(type='bool', default=False),
|
||||
namespace=dict(type="str"),
|
||||
all_images=dict(type="bool", default=True),
|
||||
keep_younger_than=dict(type="int"),
|
||||
prune_over_size_limit=dict(type="bool", default=False),
|
||||
registry_url=dict(type="str"),
|
||||
registry_validate_certs=dict(type="bool"),
|
||||
registry_ca_cert=dict(type="path"),
|
||||
prune_registry=dict(type="bool", default=True),
|
||||
ignore_invalid_refs=dict(type="bool", default=False),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_images import (
|
||||
OpenShiftAdmPruneImages
|
||||
OpenShiftAdmPruneImages,
|
||||
)
|
||||
|
||||
module = OpenShiftAdmPruneImages(argument_spec=argument_spec(), supports_check_mode=True)
|
||||
module = OpenShiftAdmPruneImages(
|
||||
argument_spec=argument_spec(), supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_auth
|
||||
|
||||
@@ -74,46 +75,49 @@ requirements:
|
||||
- urllib3
|
||||
- requests
|
||||
- requests-oauthlib
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
- hosts: localhost
|
||||
EXAMPLES = r"""
|
||||
- name: Example Playbook
|
||||
hosts: localhost
|
||||
module_defaults:
|
||||
group/community.okd.okd:
|
||||
host: https://k8s.example.com/
|
||||
ca_cert: ca.pem
|
||||
tasks:
|
||||
- block:
|
||||
# It's good practice to store login credentials in a secure vault and not
|
||||
# directly in playbooks.
|
||||
- include_vars: openshift_passwords.yml
|
||||
- name: Authenticate to OpenShift cluster and gell a list of all pods from any namespace
|
||||
block:
|
||||
# It's good practice to store login credentials in a secure vault and not
|
||||
# directly in playbooks.
|
||||
- name: Include 'openshift_passwords.yml'
|
||||
ansible.builtin.include_vars: openshift_passwords.yml
|
||||
|
||||
- name: Log in (obtain access token)
|
||||
community.okd.openshift_auth:
|
||||
username: admin
|
||||
password: "{{ openshift_admin_password }}"
|
||||
register: openshift_auth_results
|
||||
- name: Log in (obtain access token)
|
||||
community.okd.openshift_auth:
|
||||
username: admin
|
||||
password: "{{ openshift_admin_password }}"
|
||||
register: openshift_auth_results
|
||||
|
||||
# Previous task provides the token/api_key, while all other parameters
|
||||
# are taken from module_defaults
|
||||
- name: Get a list of all pods from any namespace
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
|
||||
kind: Pod
|
||||
register: pod_list
|
||||
# Previous task provides the token/api_key, while all other parameters
|
||||
# are taken from module_defaults
|
||||
- name: Get a list of all pods from any namespace
|
||||
kubernetes.core.k8s_info:
|
||||
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
|
||||
kind: Pod
|
||||
register: pod_list
|
||||
|
||||
always:
|
||||
- name: If login succeeded, try to log out (revoke access token)
|
||||
when: openshift_auth_results.openshift_auth.api_key is defined
|
||||
community.okd.openshift_auth:
|
||||
state: absent
|
||||
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
|
||||
'''
|
||||
always:
|
||||
- name: If login succeeded, try to log out (revoke access token)
|
||||
when: openshift_auth_results.openshift_auth.api_key is defined
|
||||
community.okd.openshift_auth:
|
||||
state: absent
|
||||
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
|
||||
"""
|
||||
|
||||
# Returned value names need to match k8s modules parameter names, to make it
|
||||
# easy to pass returned values of openshift_auth to other k8s modules.
|
||||
# Discussion: https://github.com/ansible/ansible/pull/50807#discussion_r248827899
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
openshift_auth:
|
||||
description: OpenShift authentication facts.
|
||||
returned: success
|
||||
@@ -164,7 +168,7 @@ k8s_auth:
|
||||
description: Username for authenticating with the API server.
|
||||
returned: success
|
||||
type: str
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
import traceback
|
||||
@@ -179,52 +183,52 @@ import hashlib
|
||||
# 3rd party imports
|
||||
try:
|
||||
import requests
|
||||
|
||||
HAS_REQUESTS = True
|
||||
except ImportError:
|
||||
HAS_REQUESTS = False
|
||||
|
||||
try:
|
||||
from requests_oauthlib import OAuth2Session
|
||||
|
||||
HAS_REQUESTS_OAUTH = True
|
||||
except ImportError:
|
||||
HAS_REQUESTS_OAUTH = False
|
||||
|
||||
try:
|
||||
from urllib3.util import make_headers
|
||||
|
||||
HAS_URLLIB3 = True
|
||||
except ImportError:
|
||||
HAS_URLLIB3 = False
|
||||
|
||||
|
||||
K8S_AUTH_ARG_SPEC = {
|
||||
'state': {
|
||||
'default': 'present',
|
||||
'choices': ['present', 'absent'],
|
||||
"state": {
|
||||
"default": "present",
|
||||
"choices": ["present", "absent"],
|
||||
},
|
||||
'host': {'required': True},
|
||||
'username': {},
|
||||
'password': {'no_log': True},
|
||||
'ca_cert': {'type': 'path', 'aliases': ['ssl_ca_cert']},
|
||||
'validate_certs': {
|
||||
'type': 'bool',
|
||||
'default': True,
|
||||
'aliases': ['verify_ssl']
|
||||
},
|
||||
'api_key': {'no_log': True},
|
||||
"host": {"required": True},
|
||||
"username": {},
|
||||
"password": {"no_log": True},
|
||||
"ca_cert": {"type": "path", "aliases": ["ssl_ca_cert"]},
|
||||
"validate_certs": {"type": "bool", "default": True, "aliases": ["verify_ssl"]},
|
||||
"api_key": {"no_log": True},
|
||||
}
|
||||
|
||||
|
||||
def get_oauthaccesstoken_objectname_from_token(token_name):
|
||||
|
||||
"""
|
||||
openshift convert the access token to an OAuthAccessToken resource name using the algorithm
|
||||
https://github.com/openshift/console/blob/9f352ba49f82ad693a72d0d35709961428b43b93/pkg/server/server.go#L609-L613
|
||||
openshift convert the access token to an OAuthAccessToken resource name using the algorithm
|
||||
https://github.com/openshift/console/blob/9f352ba49f82ad693a72d0d35709961428b43b93/pkg/server/server.go#L609-L613
|
||||
"""
|
||||
|
||||
sha256Prefix = "sha256~"
|
||||
content = token_name.strip(sha256Prefix)
|
||||
|
||||
b64encoded = urlsafe_b64encode(hashlib.sha256(content.encode()).digest()).rstrip(b'=')
|
||||
b64encoded = urlsafe_b64encode(hashlib.sha256(content.encode()).digest()).rstrip(
|
||||
b"="
|
||||
)
|
||||
return sha256Prefix + b64encoded.decode("utf-8")
|
||||
|
||||
|
||||
@@ -234,42 +238,48 @@ class OpenShiftAuthModule(AnsibleModule):
|
||||
self,
|
||||
argument_spec=K8S_AUTH_ARG_SPEC,
|
||||
required_if=[
|
||||
('state', 'present', ['username', 'password']),
|
||||
('state', 'absent', ['api_key']),
|
||||
]
|
||||
("state", "present", ["username", "password"]),
|
||||
("state", "absent", ["api_key"]),
|
||||
],
|
||||
)
|
||||
|
||||
if not HAS_REQUESTS:
|
||||
self.fail("This module requires the python 'requests' package. Try `pip install requests`.")
|
||||
self.fail(
|
||||
"This module requires the python 'requests' package. Try `pip install requests`."
|
||||
)
|
||||
|
||||
if not HAS_REQUESTS_OAUTH:
|
||||
self.fail("This module requires the python 'requests-oauthlib' package. Try `pip install requests-oauthlib`.")
|
||||
self.fail(
|
||||
"This module requires the python 'requests-oauthlib' package. Try `pip install requests-oauthlib`."
|
||||
)
|
||||
|
||||
if not HAS_URLLIB3:
|
||||
self.fail("This module requires the python 'urllib3' package. Try `pip install urllib3`.")
|
||||
self.fail(
|
||||
"This module requires the python 'urllib3' package. Try `pip install urllib3`."
|
||||
)
|
||||
|
||||
def execute_module(self):
|
||||
state = self.params.get('state')
|
||||
verify_ssl = self.params.get('validate_certs')
|
||||
ssl_ca_cert = self.params.get('ca_cert')
|
||||
state = self.params.get("state")
|
||||
verify_ssl = self.params.get("validate_certs")
|
||||
ssl_ca_cert = self.params.get("ca_cert")
|
||||
|
||||
self.auth_username = self.params.get('username')
|
||||
self.auth_password = self.params.get('password')
|
||||
self.auth_api_key = self.params.get('api_key')
|
||||
self.con_host = self.params.get('host')
|
||||
self.auth_username = self.params.get("username")
|
||||
self.auth_password = self.params.get("password")
|
||||
self.auth_api_key = self.params.get("api_key")
|
||||
self.con_host = self.params.get("host")
|
||||
|
||||
# python-requests takes either a bool or a path to a ca file as the 'verify' param
|
||||
if verify_ssl and ssl_ca_cert:
|
||||
self.con_verify_ca = ssl_ca_cert # path
|
||||
else:
|
||||
self.con_verify_ca = verify_ssl # bool
|
||||
self.con_verify_ca = verify_ssl # bool
|
||||
|
||||
# Get needed info to access authorization APIs
|
||||
self.openshift_discover()
|
||||
|
||||
changed = False
|
||||
result = dict()
|
||||
if state == 'present':
|
||||
if state == "present":
|
||||
new_api_key = self.openshift_login()
|
||||
result = dict(
|
||||
host=self.con_host,
|
||||
@@ -285,87 +295,114 @@ class OpenShiftAuthModule(AnsibleModule):
|
||||
self.exit_json(changed=changed, openshift_auth=result, k8s_auth=result)
|
||||
|
||||
def openshift_discover(self):
|
||||
url = urljoin(self.con_host, '.well-known/oauth-authorization-server')
|
||||
url = urljoin(self.con_host, ".well-known/oauth-authorization-server")
|
||||
ret = requests.get(url, verify=self.con_verify_ca)
|
||||
|
||||
if ret.status_code != 200:
|
||||
self.fail_request("Couldn't find OpenShift's OAuth API", method='GET', url=url,
|
||||
reason=ret.reason, status_code=ret.status_code)
|
||||
self.fail_request(
|
||||
"Couldn't find OpenShift's OAuth API",
|
||||
method="GET",
|
||||
url=url,
|
||||
reason=ret.reason,
|
||||
status_code=ret.status_code,
|
||||
)
|
||||
|
||||
try:
|
||||
oauth_info = ret.json()
|
||||
|
||||
self.openshift_auth_endpoint = oauth_info['authorization_endpoint']
|
||||
self.openshift_token_endpoint = oauth_info['token_endpoint']
|
||||
self.openshift_auth_endpoint = oauth_info["authorization_endpoint"]
|
||||
self.openshift_token_endpoint = oauth_info["token_endpoint"]
|
||||
except Exception:
|
||||
self.fail_json(msg="Something went wrong discovering OpenShift OAuth details.",
|
||||
exception=traceback.format_exc())
|
||||
self.fail_json(
|
||||
msg="Something went wrong discovering OpenShift OAuth details.",
|
||||
exception=traceback.format_exc(),
|
||||
)
|
||||
|
||||
def openshift_login(self):
|
||||
os_oauth = OAuth2Session(client_id='openshift-challenging-client')
|
||||
authorization_url, state = os_oauth.authorization_url(self.openshift_auth_endpoint,
|
||||
state="1", code_challenge_method='S256')
|
||||
auth_headers = make_headers(basic_auth='{0}:{1}'.format(self.auth_username, self.auth_password))
|
||||
os_oauth = OAuth2Session(client_id="openshift-challenging-client")
|
||||
authorization_url, state = os_oauth.authorization_url(
|
||||
self.openshift_auth_endpoint, state="1", code_challenge_method="S256"
|
||||
)
|
||||
auth_headers = make_headers(
|
||||
basic_auth="{0}:{1}".format(self.auth_username, self.auth_password)
|
||||
)
|
||||
|
||||
# Request authorization code using basic auth credentials
|
||||
ret = os_oauth.get(
|
||||
authorization_url,
|
||||
headers={'X-Csrf-Token': state, 'authorization': auth_headers.get('authorization')},
|
||||
headers={
|
||||
"X-Csrf-Token": state,
|
||||
"authorization": auth_headers.get("authorization"),
|
||||
},
|
||||
verify=self.con_verify_ca,
|
||||
allow_redirects=False
|
||||
allow_redirects=False,
|
||||
)
|
||||
|
||||
if ret.status_code != 302:
|
||||
self.fail_request("Authorization failed.", method='GET', url=authorization_url,
|
||||
reason=ret.reason, status_code=ret.status_code)
|
||||
self.fail_request(
|
||||
"Authorization failed.",
|
||||
method="GET",
|
||||
url=authorization_url,
|
||||
reason=ret.reason,
|
||||
status_code=ret.status_code,
|
||||
)
|
||||
|
||||
# In here we have `code` and `state`, I think `code` is the important one
|
||||
qwargs = {}
|
||||
for k, v in parse_qs(urlparse(ret.headers['Location']).query).items():
|
||||
for k, v in parse_qs(urlparse(ret.headers["Location"]).query).items():
|
||||
qwargs[k] = v[0]
|
||||
qwargs['grant_type'] = 'authorization_code'
|
||||
qwargs["grant_type"] = "authorization_code"
|
||||
|
||||
# Using authorization code given to us in the Location header of the previous request, request a token
|
||||
ret = os_oauth.post(
|
||||
self.openshift_token_endpoint,
|
||||
headers={
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
# This is just base64 encoded 'openshift-challenging-client:'
|
||||
'Authorization': 'Basic b3BlbnNoaWZ0LWNoYWxsZW5naW5nLWNsaWVudDo='
|
||||
"Authorization": "Basic b3BlbnNoaWZ0LWNoYWxsZW5naW5nLWNsaWVudDo=",
|
||||
},
|
||||
data=urlencode(qwargs),
|
||||
verify=self.con_verify_ca
|
||||
verify=self.con_verify_ca,
|
||||
)
|
||||
|
||||
if ret.status_code != 200:
|
||||
self.fail_request("Failed to obtain an authorization token.", method='POST',
|
||||
url=self.openshift_token_endpoint,
|
||||
reason=ret.reason, status_code=ret.status_code)
|
||||
self.fail_request(
|
||||
"Failed to obtain an authorization token.",
|
||||
method="POST",
|
||||
url=self.openshift_token_endpoint,
|
||||
reason=ret.reason,
|
||||
status_code=ret.status_code,
|
||||
)
|
||||
|
||||
return ret.json()['access_token']
|
||||
return ret.json()["access_token"]
|
||||
|
||||
def openshift_logout(self):
|
||||
|
||||
name = get_oauthaccesstoken_objectname_from_token(self.auth_api_key)
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': "Bearer {0}".format(self.auth_api_key)
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {0}".format(self.auth_api_key),
|
||||
}
|
||||
|
||||
url = "{0}/apis/oauth.openshift.io/v1/useroauthaccesstokens/{1}".format(self.con_host, name)
|
||||
url = "{0}/apis/oauth.openshift.io/v1/useroauthaccesstokens/{1}".format(
|
||||
self.con_host, name
|
||||
)
|
||||
json = {
|
||||
"apiVersion": "oauth.openshift.io/v1",
|
||||
"kind": "DeleteOptions",
|
||||
"gracePeriodSeconds": 0
|
||||
"gracePeriodSeconds": 0,
|
||||
}
|
||||
|
||||
ret = requests.delete(url, json=json, verify=self.con_verify_ca, headers=headers)
|
||||
ret = requests.delete(
|
||||
url, json=json, verify=self.con_verify_ca, headers=headers
|
||||
)
|
||||
if ret.status_code != 200:
|
||||
self.fail_json(
|
||||
msg="Couldn't delete user oauth access token '{0}' due to: {1}".format(name, ret.json().get("message")),
|
||||
status_code=ret.status_code
|
||||
msg="Couldn't delete user oauth access token '{0}' due to: {1}".format(
|
||||
name, ret.json().get("message")
|
||||
),
|
||||
status_code=ret.status_code,
|
||||
)
|
||||
|
||||
return True
|
||||
@@ -376,7 +413,7 @@ class OpenShiftAuthModule(AnsibleModule):
|
||||
def fail_request(self, msg, **kwargs):
|
||||
req_info = {}
|
||||
for k, v in kwargs.items():
|
||||
req_info['req_' + k] = v
|
||||
req_info["req_" + k] = v
|
||||
self.fail_json(msg=msg, **req_info)
|
||||
|
||||
|
||||
@@ -388,5 +425,5 @@ def main():
|
||||
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_build
|
||||
|
||||
@@ -134,9 +135,9 @@ options:
|
||||
requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# Starts build from build config default/hello-world
|
||||
- name: Starts build from build config
|
||||
community.okd.openshift_build:
|
||||
@@ -171,9 +172,9 @@ EXAMPLES = r'''
|
||||
build_phases:
|
||||
- New
|
||||
state: cancelled
|
||||
'''
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
builds:
|
||||
description:
|
||||
- The builds that were started/cancelled.
|
||||
@@ -200,37 +201,47 @@ builds:
|
||||
description: Current status details for the object.
|
||||
returned: success
|
||||
type: dict
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
|
||||
args_options = dict(
|
||||
name=dict(type='str', required=True),
|
||||
value=dict(type='str', required=True)
|
||||
name=dict(type="str", required=True), value=dict(type="str", required=True)
|
||||
)
|
||||
|
||||
args.update(
|
||||
dict(
|
||||
state=dict(type='str', choices=['started', 'cancelled', 'restarted'], default="started"),
|
||||
build_args=dict(type='list', elements='dict', options=args_options),
|
||||
commit=dict(type='str'),
|
||||
env_vars=dict(type='list', elements='dict', options=args_options),
|
||||
build_name=dict(type='str'),
|
||||
build_config_name=dict(type='str'),
|
||||
namespace=dict(type='str', required=True),
|
||||
incremental=dict(type='bool'),
|
||||
no_cache=dict(type='bool'),
|
||||
wait=dict(type='bool', default=False),
|
||||
wait_sleep=dict(type='int', default=5),
|
||||
wait_timeout=dict(type='int', default=120),
|
||||
build_phases=dict(type='list', elements='str', default=[], choices=["New", "Pending", "Running"]),
|
||||
state=dict(
|
||||
type="str",
|
||||
choices=["started", "cancelled", "restarted"],
|
||||
default="started",
|
||||
),
|
||||
build_args=dict(type="list", elements="dict", options=args_options),
|
||||
commit=dict(type="str"),
|
||||
env_vars=dict(type="list", elements="dict", options=args_options),
|
||||
build_name=dict(type="str"),
|
||||
build_config_name=dict(type="str"),
|
||||
namespace=dict(type="str", required=True),
|
||||
incremental=dict(type="bool"),
|
||||
no_cache=dict(type="bool"),
|
||||
wait=dict(type="bool", default=False),
|
||||
wait_sleep=dict(type="int", default=5),
|
||||
wait_timeout=dict(type="int", default=120),
|
||||
build_phases=dict(
|
||||
type="list",
|
||||
elements="str",
|
||||
default=[],
|
||||
choices=["New", "Pending", "Running"],
|
||||
),
|
||||
)
|
||||
)
|
||||
return args
|
||||
@@ -238,23 +249,24 @@ def argument_spec():
|
||||
|
||||
def main():
|
||||
mutually_exclusive = [
|
||||
('build_name', 'build_config_name'),
|
||||
("build_name", "build_config_name"),
|
||||
]
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import (
|
||||
OpenShiftBuilds
|
||||
OpenShiftBuilds,
|
||||
)
|
||||
|
||||
module = OpenShiftBuilds(
|
||||
argument_spec=argument_spec(),
|
||||
mutually_exclusive=mutually_exclusive,
|
||||
required_one_of=[
|
||||
[
|
||||
'build_name',
|
||||
'build_config_name',
|
||||
"build_name",
|
||||
"build_config_name",
|
||||
]
|
||||
],
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_import_image
|
||||
|
||||
@@ -75,9 +76,9 @@ requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
- docker-image-py
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# Import tag latest into a new image stream.
|
||||
- name: Import tag latest into new image stream
|
||||
community.okd.openshift_import_image:
|
||||
@@ -122,10 +123,10 @@ EXAMPLES = r'''
|
||||
- mystream3
|
||||
source: registry.io/repo/image:latest
|
||||
all: true
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
result:
|
||||
description:
|
||||
- List with all ImageStreamImport that have been created.
|
||||
@@ -153,42 +154,44 @@ result:
|
||||
description: Current status details for the object.
|
||||
returned: success
|
||||
type: dict
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
namespace=dict(type='str', required=True),
|
||||
name=dict(type='raw', required=True),
|
||||
all=dict(type='bool', default=False),
|
||||
validate_registry_certs=dict(type='bool'),
|
||||
reference_policy=dict(type='str', choices=["source", "local"], default="source"),
|
||||
scheduled=dict(type='bool', default=False),
|
||||
source=dict(type='str'),
|
||||
namespace=dict(type="str", required=True),
|
||||
name=dict(type="raw", required=True),
|
||||
all=dict(type="bool", default=False),
|
||||
validate_registry_certs=dict(type="bool"),
|
||||
reference_policy=dict(
|
||||
type="str", choices=["source", "local"], default="source"
|
||||
),
|
||||
scheduled=dict(type="bool", default=False),
|
||||
source=dict(type="str"),
|
||||
)
|
||||
)
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_import_image import (
|
||||
OpenShiftImportImage
|
||||
OpenShiftImportImage,
|
||||
)
|
||||
|
||||
module = OpenShiftImportImage(
|
||||
argument_spec=argument_spec(),
|
||||
supports_check_mode=True
|
||||
argument_spec=argument_spec(), supports_check_mode=True
|
||||
)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# Copyright (c) 2020-2021, Red Hat
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
module: openshift_process
|
||||
|
||||
short_description: Process an OpenShift template.openshift.io/v1 Template
|
||||
@@ -49,6 +50,7 @@ options:
|
||||
description:
|
||||
- The namespace that resources should be created, updated, or deleted in.
|
||||
- Only used when I(state) is present or absent.
|
||||
type: str
|
||||
parameters:
|
||||
description:
|
||||
- 'A set of key: value pairs that will be used to set/override values in the Template.'
|
||||
@@ -70,9 +72,9 @@ options:
|
||||
type: str
|
||||
default: rendered
|
||||
choices: [ absent, present, rendered ]
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
- name: Process a template in the cluster
|
||||
community.okd.openshift_process:
|
||||
name: nginx-example
|
||||
@@ -87,8 +89,8 @@ EXAMPLES = r'''
|
||||
community.okd.k8s:
|
||||
namespace: default
|
||||
definition: '{{ item }}'
|
||||
wait: yes
|
||||
apply: yes
|
||||
wait: true
|
||||
apply: true
|
||||
loop: '{{ result.resources }}'
|
||||
|
||||
- name: Process a template with parameters from an env file and create the resources
|
||||
@@ -98,7 +100,7 @@ EXAMPLES = r'''
|
||||
namespace_target: default
|
||||
parameter_file: 'files/nginx.env'
|
||||
state: present
|
||||
wait: yes
|
||||
wait: true
|
||||
|
||||
- name: Process a local template and create the resources
|
||||
community.okd.openshift_process:
|
||||
@@ -113,10 +115,10 @@ EXAMPLES = r'''
|
||||
parameter_file: files/example.env
|
||||
namespace_target: default
|
||||
state: absent
|
||||
wait: yes
|
||||
'''
|
||||
wait: true
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
result:
|
||||
description:
|
||||
- The created, patched, or otherwise present object. Will be empty in the case of a deletion.
|
||||
@@ -200,11 +202,13 @@ resources:
|
||||
conditions:
|
||||
type: complex
|
||||
description: Array of status conditions for the object. Not guaranteed to be present
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, WAIT_ARG_SPEC
|
||||
AUTH_ARG_SPEC,
|
||||
RESOURCE_ARG_SPEC,
|
||||
WAIT_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
@@ -213,24 +217,26 @@ def argspec():
|
||||
argument_spec.update(AUTH_ARG_SPEC)
|
||||
argument_spec.update(WAIT_ARG_SPEC)
|
||||
argument_spec.update(RESOURCE_ARG_SPEC)
|
||||
argument_spec['state'] = dict(type='str', default='rendered', choices=['present', 'absent', 'rendered'])
|
||||
argument_spec['namespace'] = dict(type='str')
|
||||
argument_spec['namespace_target'] = dict(type='str')
|
||||
argument_spec['parameters'] = dict(type='dict')
|
||||
argument_spec['name'] = dict(type='str')
|
||||
argument_spec['parameter_file'] = dict(type='str')
|
||||
argument_spec["state"] = dict(
|
||||
type="str", default="rendered", choices=["present", "absent", "rendered"]
|
||||
)
|
||||
argument_spec["namespace"] = dict(type="str")
|
||||
argument_spec["namespace_target"] = dict(type="str")
|
||||
argument_spec["parameters"] = dict(type="dict")
|
||||
argument_spec["name"] = dict(type="str")
|
||||
argument_spec["parameter_file"] = dict(type="str")
|
||||
|
||||
return argument_spec
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_process import (
|
||||
OpenShiftProcess)
|
||||
OpenShiftProcess,
|
||||
)
|
||||
|
||||
module = OpenShiftProcess(argument_spec=argspec(), supports_check_mode=True)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
|
||||
module: openshift_registry_info
|
||||
|
||||
@@ -40,9 +41,9 @@ requirements:
|
||||
- python >= 3.6
|
||||
- kubernetes >= 12.0.0
|
||||
- docker-image-py
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# Get registry information
|
||||
- name: Read integrated registry information
|
||||
community.okd.openshift_registry_info:
|
||||
@@ -50,11 +51,11 @@ EXAMPLES = r'''
|
||||
# Read registry integrated information and attempt to contact using local client.
|
||||
- name: Attempt to contact integrated registry using local client
|
||||
community.okd.openshift_registry_info:
|
||||
check: yes
|
||||
'''
|
||||
check: true
|
||||
"""
|
||||
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
internal_hostname:
|
||||
description:
|
||||
- The internal registry hostname.
|
||||
@@ -79,36 +80,30 @@ check:
|
||||
description: message describing the ping operation.
|
||||
returned: always
|
||||
type: str
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC,
|
||||
)
|
||||
|
||||
|
||||
def argument_spec():
|
||||
args = copy.deepcopy(AUTH_ARG_SPEC)
|
||||
args.update(
|
||||
dict(
|
||||
check=dict(type='bool', default=False)
|
||||
)
|
||||
)
|
||||
args.update(dict(check=dict(type="bool", default=False)))
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_registry import (
|
||||
OpenShiftRegistry
|
||||
OpenShiftRegistry,
|
||||
)
|
||||
|
||||
module = OpenShiftRegistry(
|
||||
argument_spec=argument_spec(),
|
||||
supports_check_mode=True
|
||||
)
|
||||
module = OpenShiftRegistry(argument_spec=argument_spec(), supports_check_mode=True)
|
||||
module.run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
# STARTREMOVE (downstream)
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
module: openshift_route
|
||||
|
||||
short_description: Expose a Service as an OpenShift Route.
|
||||
@@ -133,9 +133,9 @@ options:
|
||||
- insecure
|
||||
default: insecure
|
||||
type: str
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
- name: Create hello-world deployment
|
||||
community.okd.k8s:
|
||||
definition:
|
||||
@@ -155,10 +155,10 @@ EXAMPLES = r'''
|
||||
app: hello-kubernetes
|
||||
spec:
|
||||
containers:
|
||||
- name: hello-kubernetes
|
||||
image: paulbouwer/hello-kubernetes:1.8
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
- name: hello-kubernetes
|
||||
image: paulbouwer/hello-kubernetes:1.8
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
|
||||
- name: Create Service for the hello-world deployment
|
||||
community.okd.k8s:
|
||||
@@ -170,8 +170,8 @@ EXAMPLES = r'''
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: hello-kubernetes
|
||||
|
||||
@@ -183,9 +183,9 @@ EXAMPLES = r'''
|
||||
annotations:
|
||||
haproxy.router.openshift.io/balance: roundrobin
|
||||
register: route
|
||||
'''
|
||||
"""
|
||||
|
||||
RETURN = r'''
|
||||
RETURN = r"""
|
||||
result:
|
||||
description:
|
||||
- The Route object that was created or updated. Will be empty in the case of deletion.
|
||||
@@ -303,20 +303,28 @@ duration:
|
||||
returned: when C(wait) is true
|
||||
type: int
|
||||
sample: 48
|
||||
'''
|
||||
"""
|
||||
# ENDREMOVE (downstream)
|
||||
|
||||
import copy
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
|
||||
AnsibleOpenshiftModule,
|
||||
)
|
||||
|
||||
try:
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import perform_action
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import Waiter
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import (
|
||||
perform_action,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import (
|
||||
Waiter,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
AUTH_ARG_SPEC, WAIT_ARG_SPEC, COMMON_ARG_SPEC
|
||||
AUTH_ARG_SPEC,
|
||||
WAIT_ARG_SPEC,
|
||||
COMMON_ARG_SPEC,
|
||||
)
|
||||
except ImportError as e:
|
||||
pass
|
||||
@@ -329,7 +337,6 @@ except ImportError:
|
||||
|
||||
|
||||
class OpenShiftRoute(AnsibleOpenshiftModule):
|
||||
|
||||
def __init__(self):
|
||||
super(OpenShiftRoute, self).__init__(
|
||||
argument_spec=self.argspec,
|
||||
@@ -339,7 +346,7 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
|
||||
self.append_hash = False
|
||||
self.apply = False
|
||||
self.warnings = []
|
||||
self.params['merge_type'] = None
|
||||
self.params["merge_type"] = None
|
||||
|
||||
@property
|
||||
def argspec(self):
|
||||
@@ -347,80 +354,95 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
|
||||
spec.update(copy.deepcopy(WAIT_ARG_SPEC))
|
||||
spec.update(copy.deepcopy(COMMON_ARG_SPEC))
|
||||
|
||||
spec['service'] = dict(type='str', aliases=['svc'])
|
||||
spec['namespace'] = dict(required=True, type='str')
|
||||
spec['labels'] = dict(type='dict')
|
||||
spec['name'] = dict(type='str')
|
||||
spec['hostname'] = dict(type='str')
|
||||
spec['path'] = dict(type='str')
|
||||
spec['wildcard_policy'] = dict(choices=['Subdomain'], type='str')
|
||||
spec['port'] = dict(type='str')
|
||||
spec['tls'] = dict(type='dict', options=dict(
|
||||
ca_certificate=dict(type='str'),
|
||||
certificate=dict(type='str'),
|
||||
destination_ca_certificate=dict(type='str'),
|
||||
key=dict(type='str', no_log=False),
|
||||
insecure_policy=dict(type='str', choices=['allow', 'redirect', 'disallow'], default='disallow'),
|
||||
))
|
||||
spec['termination'] = dict(choices=['edge', 'passthrough', 'reencrypt', 'insecure'], default='insecure')
|
||||
spec['annotations'] = dict(type='dict')
|
||||
spec["service"] = dict(type="str", aliases=["svc"])
|
||||
spec["namespace"] = dict(required=True, type="str")
|
||||
spec["labels"] = dict(type="dict")
|
||||
spec["name"] = dict(type="str")
|
||||
spec["hostname"] = dict(type="str")
|
||||
spec["path"] = dict(type="str")
|
||||
spec["wildcard_policy"] = dict(choices=["Subdomain"], type="str")
|
||||
spec["port"] = dict(type="str")
|
||||
spec["tls"] = dict(
|
||||
type="dict",
|
||||
options=dict(
|
||||
ca_certificate=dict(type="str"),
|
||||
certificate=dict(type="str"),
|
||||
destination_ca_certificate=dict(type="str"),
|
||||
key=dict(type="str", no_log=False),
|
||||
insecure_policy=dict(
|
||||
type="str",
|
||||
choices=["allow", "redirect", "disallow"],
|
||||
default="disallow",
|
||||
),
|
||||
),
|
||||
)
|
||||
spec["termination"] = dict(
|
||||
choices=["edge", "passthrough", "reencrypt", "insecure"], default="insecure"
|
||||
)
|
||||
spec["annotations"] = dict(type="dict")
|
||||
|
||||
return spec
|
||||
|
||||
def execute_module(self):
|
||||
|
||||
service_name = self.params.get('service')
|
||||
namespace = self.params['namespace']
|
||||
termination_type = self.params.get('termination')
|
||||
if termination_type == 'insecure':
|
||||
service_name = self.params.get("service")
|
||||
namespace = self.params["namespace"]
|
||||
termination_type = self.params.get("termination")
|
||||
if termination_type == "insecure":
|
||||
termination_type = None
|
||||
state = self.params.get('state')
|
||||
state = self.params.get("state")
|
||||
|
||||
if state != 'absent' and not service_name:
|
||||
if state != "absent" and not service_name:
|
||||
self.fail_json("If 'state' is not 'absent' then 'service' must be provided")
|
||||
|
||||
# We need to do something a little wonky to wait if the user doesn't supply a custom condition
|
||||
custom_wait = self.params.get('wait') and not self.params.get('wait_condition') and state != 'absent'
|
||||
custom_wait = (
|
||||
self.params.get("wait")
|
||||
and not self.params.get("wait_condition")
|
||||
and state != "absent"
|
||||
)
|
||||
if custom_wait:
|
||||
# Don't use default wait logic in perform_action
|
||||
self.params['wait'] = False
|
||||
self.params["wait"] = False
|
||||
|
||||
route_name = self.params.get('name') or service_name
|
||||
labels = self.params.get('labels')
|
||||
hostname = self.params.get('hostname')
|
||||
path = self.params.get('path')
|
||||
wildcard_policy = self.params.get('wildcard_policy')
|
||||
port = self.params.get('port')
|
||||
annotations = self.params.get('annotations')
|
||||
route_name = self.params.get("name") or service_name
|
||||
labels = self.params.get("labels")
|
||||
hostname = self.params.get("hostname")
|
||||
path = self.params.get("path")
|
||||
wildcard_policy = self.params.get("wildcard_policy")
|
||||
port = self.params.get("port")
|
||||
annotations = self.params.get("annotations")
|
||||
|
||||
if termination_type and self.params.get('tls'):
|
||||
tls_ca_cert = self.params['tls'].get('ca_certificate')
|
||||
tls_cert = self.params['tls'].get('certificate')
|
||||
tls_dest_ca_cert = self.params['tls'].get('destination_ca_certificate')
|
||||
tls_key = self.params['tls'].get('key')
|
||||
tls_insecure_policy = self.params['tls'].get('insecure_policy')
|
||||
if tls_insecure_policy == 'disallow':
|
||||
if termination_type and self.params.get("tls"):
|
||||
tls_ca_cert = self.params["tls"].get("ca_certificate")
|
||||
tls_cert = self.params["tls"].get("certificate")
|
||||
tls_dest_ca_cert = self.params["tls"].get("destination_ca_certificate")
|
||||
tls_key = self.params["tls"].get("key")
|
||||
tls_insecure_policy = self.params["tls"].get("insecure_policy")
|
||||
if tls_insecure_policy == "disallow":
|
||||
tls_insecure_policy = None
|
||||
else:
|
||||
tls_ca_cert = tls_cert = tls_dest_ca_cert = tls_key = tls_insecure_policy = None
|
||||
tls_ca_cert = (
|
||||
tls_cert
|
||||
) = tls_dest_ca_cert = tls_key = tls_insecure_policy = None
|
||||
|
||||
route = {
|
||||
'apiVersion': 'route.openshift.io/v1',
|
||||
'kind': 'Route',
|
||||
'metadata': {
|
||||
'name': route_name,
|
||||
'namespace': namespace,
|
||||
'labels': labels,
|
||||
"apiVersion": "route.openshift.io/v1",
|
||||
"kind": "Route",
|
||||
"metadata": {
|
||||
"name": route_name,
|
||||
"namespace": namespace,
|
||||
"labels": labels,
|
||||
},
|
||||
'spec': {}
|
||||
"spec": {},
|
||||
}
|
||||
|
||||
if annotations:
|
||||
route['metadata']['annotations'] = annotations
|
||||
route["metadata"]["annotations"] = annotations
|
||||
|
||||
if state != 'absent':
|
||||
route['spec'] = self.build_route_spec(
|
||||
service_name, namespace,
|
||||
if state != "absent":
|
||||
route["spec"] = self.build_route_spec(
|
||||
service_name,
|
||||
namespace,
|
||||
port=port,
|
||||
wildcard_policy=wildcard_policy,
|
||||
hostname=hostname,
|
||||
@@ -434,79 +456,120 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
|
||||
)
|
||||
|
||||
result = perform_action(self.svc, route, self.params)
|
||||
timeout = self.params.get('wait_timeout')
|
||||
sleep = self.params.get('wait_sleep')
|
||||
timeout = self.params.get("wait_timeout")
|
||||
sleep = self.params.get("wait_sleep")
|
||||
if custom_wait:
|
||||
v1_routes = self.find_resource('Route', 'route.openshift.io/v1', fail=True)
|
||||
v1_routes = self.find_resource("Route", "route.openshift.io/v1", fail=True)
|
||||
waiter = Waiter(self.client, v1_routes, wait_predicate)
|
||||
success, result['result'], result['duration'] = waiter.wait(timeout=timeout, sleep=sleep, name=route_name, namespace=namespace)
|
||||
success, result["result"], result["duration"] = waiter.wait(
|
||||
timeout=timeout, sleep=sleep, name=route_name, namespace=namespace
|
||||
)
|
||||
|
||||
self.exit_json(**result)
|
||||
|
||||
def build_route_spec(self, service_name, namespace, port=None, wildcard_policy=None, hostname=None, path=None, termination_type=None,
|
||||
tls_insecure_policy=None, tls_ca_cert=None, tls_cert=None, tls_key=None, tls_dest_ca_cert=None):
|
||||
v1_services = self.find_resource('Service', 'v1', fail=True)
|
||||
def build_route_spec(
|
||||
self,
|
||||
service_name,
|
||||
namespace,
|
||||
port=None,
|
||||
wildcard_policy=None,
|
||||
hostname=None,
|
||||
path=None,
|
||||
termination_type=None,
|
||||
tls_insecure_policy=None,
|
||||
tls_ca_cert=None,
|
||||
tls_cert=None,
|
||||
tls_key=None,
|
||||
tls_dest_ca_cert=None,
|
||||
):
|
||||
v1_services = self.find_resource("Service", "v1", fail=True)
|
||||
try:
|
||||
target_service = v1_services.get(name=service_name, namespace=namespace)
|
||||
except NotFoundError:
|
||||
if not port:
|
||||
self.fail_json(msg="You need to provide the 'port' argument when exposing a non-existent service")
|
||||
self.fail_json(
|
||||
msg="You need to provide the 'port' argument when exposing a non-existent service"
|
||||
)
|
||||
target_service = None
|
||||
except DynamicApiError as exc:
|
||||
self.fail_json(msg='Failed to retrieve service to be exposed: {0}'.format(exc.body),
|
||||
error=exc.status, status=exc.status, reason=exc.reason)
|
||||
self.fail_json(
|
||||
msg="Failed to retrieve service to be exposed: {0}".format(exc.body),
|
||||
error=exc.status,
|
||||
status=exc.status,
|
||||
reason=exc.reason,
|
||||
)
|
||||
except Exception as exc:
|
||||
self.fail_json(msg='Failed to retrieve service to be exposed: {0}'.format(to_native(exc)),
|
||||
error='', status='', reason='')
|
||||
self.fail_json(
|
||||
msg="Failed to retrieve service to be exposed: {0}".format(
|
||||
to_native(exc)
|
||||
),
|
||||
error="",
|
||||
status="",
|
||||
reason="",
|
||||
)
|
||||
|
||||
route_spec = {
|
||||
'tls': {},
|
||||
'to': {
|
||||
'kind': 'Service',
|
||||
'name': service_name,
|
||||
"tls": {},
|
||||
"to": {
|
||||
"kind": "Service",
|
||||
"name": service_name,
|
||||
},
|
||||
'port': {
|
||||
'targetPort': self.set_port(target_service, port),
|
||||
"port": {
|
||||
"targetPort": self.set_port(target_service, port),
|
||||
},
|
||||
'wildcardPolicy': wildcard_policy
|
||||
"wildcardPolicy": wildcard_policy,
|
||||
}
|
||||
|
||||
# Want to conditionally add these so we don't overwrite what is automically added when nothing is provided
|
||||
if termination_type:
|
||||
route_spec['tls'] = dict(termination=termination_type.capitalize())
|
||||
route_spec["tls"] = dict(termination=termination_type.capitalize())
|
||||
if tls_insecure_policy:
|
||||
if termination_type == 'edge':
|
||||
route_spec['tls']['insecureEdgeTerminationPolicy'] = tls_insecure_policy.capitalize()
|
||||
elif termination_type == 'passthrough':
|
||||
if tls_insecure_policy != 'redirect':
|
||||
self.fail_json("'redirect' is the only supported insecureEdgeTerminationPolicy for passthrough routes")
|
||||
route_spec['tls']['insecureEdgeTerminationPolicy'] = tls_insecure_policy.capitalize()
|
||||
elif termination_type == 'reencrypt':
|
||||
self.fail_json("'tls.insecure_policy' is not supported with reencrypt routes")
|
||||
if termination_type == "edge":
|
||||
route_spec["tls"][
|
||||
"insecureEdgeTerminationPolicy"
|
||||
] = tls_insecure_policy.capitalize()
|
||||
elif termination_type == "passthrough":
|
||||
if tls_insecure_policy != "redirect":
|
||||
self.fail_json(
|
||||
"'redirect' is the only supported insecureEdgeTerminationPolicy for passthrough routes"
|
||||
)
|
||||
route_spec["tls"][
|
||||
"insecureEdgeTerminationPolicy"
|
||||
] = tls_insecure_policy.capitalize()
|
||||
elif termination_type == "reencrypt":
|
||||
self.fail_json(
|
||||
"'tls.insecure_policy' is not supported with reencrypt routes"
|
||||
)
|
||||
else:
|
||||
route_spec['tls']['insecureEdgeTerminationPolicy'] = None
|
||||
route_spec["tls"]["insecureEdgeTerminationPolicy"] = None
|
||||
if tls_ca_cert:
|
||||
if termination_type == 'passthrough':
|
||||
self.fail_json("'tls.ca_certificate' is not supported with passthrough routes")
|
||||
route_spec['tls']['caCertificate'] = tls_ca_cert
|
||||
if termination_type == "passthrough":
|
||||
self.fail_json(
|
||||
"'tls.ca_certificate' is not supported with passthrough routes"
|
||||
)
|
||||
route_spec["tls"]["caCertificate"] = tls_ca_cert
|
||||
if tls_cert:
|
||||
if termination_type == 'passthrough':
|
||||
self.fail_json("'tls.certificate' is not supported with passthrough routes")
|
||||
route_spec['tls']['certificate'] = tls_cert
|
||||
if termination_type == "passthrough":
|
||||
self.fail_json(
|
||||
"'tls.certificate' is not supported with passthrough routes"
|
||||
)
|
||||
route_spec["tls"]["certificate"] = tls_cert
|
||||
if tls_key:
|
||||
if termination_type == 'passthrough':
|
||||
if termination_type == "passthrough":
|
||||
self.fail_json("'tls.key' is not supported with passthrough routes")
|
||||
route_spec['tls']['key'] = tls_key
|
||||
route_spec["tls"]["key"] = tls_key
|
||||
if tls_dest_ca_cert:
|
||||
if termination_type != 'reencrypt':
|
||||
self.fail_json("'destination_certificate' is only valid for reencrypt routes")
|
||||
route_spec['tls']['destinationCACertificate'] = tls_dest_ca_cert
|
||||
if termination_type != "reencrypt":
|
||||
self.fail_json(
|
||||
"'destination_certificate' is only valid for reencrypt routes"
|
||||
)
|
||||
route_spec["tls"]["destinationCACertificate"] = tls_dest_ca_cert
|
||||
else:
|
||||
route_spec['tls'] = None
|
||||
route_spec["tls"] = None
|
||||
if hostname:
|
||||
route_spec['host'] = hostname
|
||||
route_spec["host"] = hostname
|
||||
if path:
|
||||
route_spec['path'] = path
|
||||
route_spec["path"] = path
|
||||
|
||||
return route_spec
|
||||
|
||||
@@ -514,7 +577,7 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
|
||||
if port_arg:
|
||||
return port_arg
|
||||
for p in service.spec.ports:
|
||||
if p.protocol == 'TCP':
|
||||
if p.protocol == "TCP":
|
||||
if p.name is not None:
|
||||
return p.name
|
||||
return p.targetPort
|
||||
@@ -525,7 +588,7 @@ def wait_predicate(route):
|
||||
if not (route.status and route.status.ingress):
|
||||
return False
|
||||
for ingress in route.status.ingress:
|
||||
match = [x for x in ingress.conditions if x.type == 'Admitted']
|
||||
match = [x for x in ingress.conditions if x.type == "Admitted"]
|
||||
if not match:
|
||||
return False
|
||||
match = match[0]
|
||||
@@ -538,5 +601,5 @@ def main():
|
||||
OpenShiftRoute().run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
collections:
|
||||
- name: kubernetes.core
|
||||
version: '>=2.4.0'
|
||||
|
||||
@@ -2,3 +2,4 @@ coverage==4.5.4
|
||||
pytest
|
||||
pytest-xdist
|
||||
pytest-forked
|
||||
pytest-ansible
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
---
|
||||
modules:
|
||||
python_requires: ">=3.6"
|
||||
python_requires: ">=3.9"
|
||||
|
||||
3
tests/sanity/ignore-2.16.txt
Normal file
3
tests/sanity/ignore-2.16.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s.py validate-modules:return-syntax-error
|
||||
plugins/modules/openshift_process.py validate-modules:parameter-type-not-in-doc
|
||||
3
tests/sanity/ignore-2.17.txt
Normal file
3
tests/sanity/ignore-2.17.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
plugins/modules/k8s.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/k8s.py validate-modules:return-syntax-error
|
||||
plugins/modules/openshift_process.py validate-modules:parameter-type-not-in-doc
|
||||
5
tests/sanity/requirements.yml
Normal file
5
tests/sanity/requirements.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
collections:
|
||||
- name: https://github.com/ansible-collections/kubernetes.core.git
|
||||
type: git
|
||||
version: main
|
||||
@@ -5,28 +5,44 @@ __metaclass__ = type
|
||||
|
||||
from ansible_collections.community.okd.plugins.module_utils.openshift_ldap import (
|
||||
openshift_equal_dn,
|
||||
openshift_ancestorof_dn
|
||||
openshift_ancestorof_dn,
|
||||
)
|
||||
import pytest
|
||||
|
||||
try:
|
||||
import ldap
|
||||
import ldap # pylint: disable=unused-import
|
||||
except ImportError:
|
||||
pytestmark = pytest.mark.skip("This test requires the python-ldap library")
|
||||
|
||||
|
||||
def test_equal_dn():
|
||||
|
||||
assert openshift_equal_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=com")
|
||||
assert not openshift_equal_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=units,ou=users,dc=ansible,dc=com")
|
||||
assert not openshift_equal_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=user,dc=ansible,dc=com")
|
||||
assert not openshift_equal_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=org")
|
||||
assert openshift_equal_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert not openshift_equal_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=units,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert not openshift_equal_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=user,dc=ansible,dc=com"
|
||||
)
|
||||
assert not openshift_equal_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=org"
|
||||
)
|
||||
|
||||
|
||||
def test_ancestor_of_dn():
|
||||
|
||||
assert not openshift_ancestorof_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=com")
|
||||
assert not openshift_ancestorof_dn("cn=unit,ou=users,dc=ansible,dc=com", "cn=units,ou=users,dc=ansible,dc=com")
|
||||
assert openshift_ancestorof_dn("ou=users,dc=ansible,dc=com", "cn=john,ou=users,dc=ansible,dc=com")
|
||||
assert openshift_ancestorof_dn("ou=users,dc=ansible,dc=com", "cn=mathew,ou=users,dc=ansible,dc=com")
|
||||
assert not openshift_ancestorof_dn("ou=users,dc=ansible,dc=com", "cn=mathew,ou=users,dc=ansible,dc=org")
|
||||
assert not openshift_ancestorof_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=unit,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert not openshift_ancestorof_dn(
|
||||
"cn=unit,ou=users,dc=ansible,dc=com", "cn=units,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert openshift_ancestorof_dn(
|
||||
"ou=users,dc=ansible,dc=com", "cn=john,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert openshift_ancestorof_dn(
|
||||
"ou=users,dc=ansible,dc=com", "cn=mathew,ou=users,dc=ansible,dc=com"
|
||||
)
|
||||
assert not openshift_ancestorof_dn(
|
||||
"ou=users,dc=ansible,dc=com", "cn=mathew,ou=users,dc=ansible,dc=org"
|
||||
)
|
||||
|
||||
@@ -9,28 +9,26 @@ from ansible_collections.community.okd.plugins.module_utils.openshift_ldap impor
|
||||
|
||||
|
||||
def test_missing_url():
|
||||
config = dict(
|
||||
kind="LDAPSyncConfig",
|
||||
apiVersion="v1",
|
||||
insecure=True
|
||||
)
|
||||
config = dict(kind="LDAPSyncConfig", apiVersion="v1", insecure=True)
|
||||
err = validate_ldap_sync_config(config)
|
||||
assert err == "url should be non empty attribute."
|
||||
|
||||
|
||||
def test_binddn_and_bindpwd_linked():
|
||||
"""
|
||||
one of bind_dn and bind_pwd cannot be set alone
|
||||
one of bind_dn and bind_pwd cannot be set alone
|
||||
"""
|
||||
config = dict(
|
||||
kind="LDAPSyncConfig",
|
||||
apiVersion="v1",
|
||||
url="ldap://LDAP_SERVICE_IP:389",
|
||||
insecure=True,
|
||||
bindDN="cn=admin,dc=example,dc=org"
|
||||
bindDN="cn=admin,dc=example,dc=org",
|
||||
)
|
||||
|
||||
credentials_error = "bindDN and bindPassword must both be specified, or both be empty."
|
||||
credentials_error = (
|
||||
"bindDN and bindPassword must both be specified, or both be empty."
|
||||
)
|
||||
|
||||
assert validate_ldap_sync_config(config) == credentials_error
|
||||
|
||||
@@ -39,7 +37,7 @@ def test_binddn_and_bindpwd_linked():
|
||||
apiVersion="v1",
|
||||
url="ldap://LDAP_SERVICE_IP:389",
|
||||
insecure=True,
|
||||
bindPassword="testing1223"
|
||||
bindPassword="testing1223",
|
||||
)
|
||||
|
||||
assert validate_ldap_sync_config(config) == credentials_error
|
||||
@@ -53,11 +51,13 @@ def test_insecure_connection():
|
||||
insecure=True,
|
||||
)
|
||||
|
||||
assert validate_ldap_sync_config(config) == "Cannot use ldaps scheme with insecure=true."
|
||||
assert (
|
||||
validate_ldap_sync_config(config)
|
||||
== "Cannot use ldaps scheme with insecure=true."
|
||||
)
|
||||
|
||||
config.update(dict(
|
||||
url="ldap://LDAP_SERVICE_IP:389",
|
||||
ca="path/to/ca/file"
|
||||
))
|
||||
config.update(dict(url="ldap://LDAP_SERVICE_IP:389", ca="path/to/ca/file"))
|
||||
|
||||
assert validate_ldap_sync_config(config) == "Cannot specify a ca with insecure=true."
|
||||
assert (
|
||||
validate_ldap_sync_config(config) == "Cannot specify a ca with insecure=true."
|
||||
)
|
||||
|
||||
@@ -11,7 +11,6 @@ import pytest
|
||||
|
||||
|
||||
def test_convert_storage_to_bytes():
|
||||
|
||||
data = [
|
||||
("1000", 1000),
|
||||
("1000Ki", 1000 * 1024),
|
||||
@@ -54,46 +53,48 @@ def validate_docker_response(resp, **kwargs):
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_with_digest():
|
||||
|
||||
image = "registry.access.redhat.com/ubi8/dotnet-21@sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
digest="sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669")
|
||||
validate_docker_response(
|
||||
response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
digest="sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669",
|
||||
)
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_with_tag_latest():
|
||||
|
||||
image = "registry.access.redhat.com/ubi8/dotnet-21:latest"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
tag="latest")
|
||||
validate_docker_response(
|
||||
response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
tag="latest",
|
||||
)
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_with_tag_int():
|
||||
|
||||
image = "registry.access.redhat.com/ubi8/dotnet-21:0.0.1"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
tag="0.0.1")
|
||||
validate_docker_response(
|
||||
response,
|
||||
hostname="registry.access.redhat.com",
|
||||
namespace="ubi8",
|
||||
name="dotnet-21",
|
||||
tag="0.0.1",
|
||||
)
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_invalid_image():
|
||||
|
||||
# The hex value of the sha256 is not valid
|
||||
image = "registry.access.redhat.com/dotnet-21@sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
@@ -101,7 +102,6 @@ def test_parse_docker_image_ref_invalid_image():
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_without_hostname():
|
||||
|
||||
image = "ansible:2.10.0"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
@@ -110,16 +110,18 @@ def test_parse_docker_image_ref_valid_image_without_hostname():
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_without_hostname_and_with_digest():
|
||||
|
||||
image = "ansible@sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response, name="ansible", digest="sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669")
|
||||
validate_docker_response(
|
||||
response,
|
||||
name="ansible",
|
||||
digest="sha256:f7718f5efd3436e781ee4322c92ab0c4ae63e61f5b36f1473a57874cc3522669",
|
||||
)
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_with_name_only():
|
||||
|
||||
image = "ansible"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
@@ -128,25 +130,27 @@ def test_parse_docker_image_ref_valid_image_with_name_only():
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_without_hostname_with_namespace_and_name():
|
||||
|
||||
image = "ibmcom/pause@sha256:fcaff905397ba63fd376d0c3019f1f1cb6e7506131389edbcb3d22719f1ae54d"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response,
|
||||
name="pause",
|
||||
namespace="ibmcom",
|
||||
digest="sha256:fcaff905397ba63fd376d0c3019f1f1cb6e7506131389edbcb3d22719f1ae54d")
|
||||
validate_docker_response(
|
||||
response,
|
||||
name="pause",
|
||||
namespace="ibmcom",
|
||||
digest="sha256:fcaff905397ba63fd376d0c3019f1f1cb6e7506131389edbcb3d22719f1ae54d",
|
||||
)
|
||||
|
||||
|
||||
def test_parse_docker_image_ref_valid_image_with_complex_namespace_name():
|
||||
|
||||
image = "registry.redhat.io/jboss-webserver-5/webserver54-openjdk11-tomcat9-openshift-rhel7:1.0"
|
||||
response, err = parse_docker_image_ref(image)
|
||||
assert err is None
|
||||
|
||||
validate_docker_response(response,
|
||||
hostname="registry.redhat.io",
|
||||
name="webserver54-openjdk11-tomcat9-openshift-rhel7",
|
||||
namespace="jboss-webserver-5",
|
||||
tag="1.0")
|
||||
validate_docker_response(
|
||||
response,
|
||||
hostname="registry.redhat.io",
|
||||
name="webserver54-openjdk11-tomcat9-openshift-rhel7",
|
||||
namespace="jboss-webserver-5",
|
||||
tag="1.0",
|
||||
)
|
||||
|
||||
37
tox.ini
Normal file
37
tox.ini
Normal file
@@ -0,0 +1,37 @@
|
||||
[tox]
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
install_command = pip install {opts} {packages}
|
||||
|
||||
[testenv:black]
|
||||
deps =
|
||||
black >= 23.0, < 24.0
|
||||
|
||||
commands =
|
||||
black {toxinidir}/plugins {toxinidir}/tests
|
||||
|
||||
[testenv:ansible-lint]
|
||||
deps =
|
||||
ansible-lint==6.21.0
|
||||
changedir = {toxinidir}
|
||||
commands =
|
||||
ansible-lint
|
||||
|
||||
[testenv:linters]
|
||||
deps =
|
||||
flake8
|
||||
{[testenv:black]deps}
|
||||
|
||||
commands =
|
||||
black -v --check --diff {toxinidir}/plugins {toxinidir}/tests
|
||||
flake8 {toxinidir}
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
exclude = .git,.tox,tests/output
|
||||
ignore = E123,E125,E203,E402,E501,E741,F401,F811,F841,W503
|
||||
max-line-length = 160
|
||||
builtins = _
|
||||
Reference in New Issue
Block a user