mirror of
https://github.com/kubernetes-sigs/kubespray.git
synced 2025-12-14 22:04:43 +03:00
Compare commits
11 Commits
symlinketc
...
v2.23.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10679ebb5d | ||
|
|
8775dcf92f | ||
|
|
bd382a9c39 | ||
|
|
ffacfe3ede | ||
|
|
7dcc22fe8c | ||
|
|
47ed2b115d | ||
|
|
b9fc4ec43e | ||
|
|
7bd757da5f | ||
|
|
9dc2092042 | ||
|
|
c7cfd32c40 | ||
|
|
a4b0656d9b |
@@ -36,8 +36,3 @@ exclude_paths:
|
|||||||
# Generated files
|
# Generated files
|
||||||
- tests/files/custom_cni/cilium.yaml
|
- tests/files/custom_cni/cilium.yaml
|
||||||
- venv
|
- venv
|
||||||
- .github
|
|
||||||
- .ansible
|
|
||||||
- .cache
|
|
||||||
mock_modules:
|
|
||||||
- gluster.gluster.gluster_volume
|
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ roles/kubernetes/control-plane/defaults/main/main.yml jinja[spacing]
|
|||||||
roles/kubernetes/kubeadm/defaults/main.yml jinja[spacing]
|
roles/kubernetes/kubeadm/defaults/main.yml jinja[spacing]
|
||||||
roles/kubernetes/node/defaults/main.yml jinja[spacing]
|
roles/kubernetes/node/defaults/main.yml jinja[spacing]
|
||||||
roles/kubernetes/preinstall/defaults/main.yml jinja[spacing]
|
roles/kubernetes/preinstall/defaults/main.yml jinja[spacing]
|
||||||
roles/kubespray-defaults/defaults/main/main.yml jinja[spacing]
|
roles/kubespray-defaults/defaults/main.yaml jinja[spacing]
|
||||||
|
|||||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
|||||||
docs/_sidebar.md linguist-generated=true
|
|
||||||
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Report a bug encountered while operating Kubernetes
|
||||||
|
labels: kind/bug
|
||||||
|
|
||||||
|
---
|
||||||
|
<!--
|
||||||
|
Please, be ready for followup questions, and please respond in a timely
|
||||||
|
manner. If we can't reproduce a bug or think a feature already exists, we
|
||||||
|
might close your issue. If we're wrong, PLEASE feel free to reopen it and
|
||||||
|
explain why.
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Environment**:
|
||||||
|
- **Cloud provider or hardware configuration:**
|
||||||
|
|
||||||
|
- **OS (`printf "$(uname -srm)\n$(cat /etc/os-release)\n"`):**
|
||||||
|
|
||||||
|
- **Version of Ansible** (`ansible --version`):
|
||||||
|
|
||||||
|
- **Version of Python** (`python --version`):
|
||||||
|
|
||||||
|
|
||||||
|
**Kubespray version (commit) (`git rev-parse --short HEAD`):**
|
||||||
|
|
||||||
|
|
||||||
|
**Network plugin used**:
|
||||||
|
|
||||||
|
|
||||||
|
**Full inventory with variables (`ansible -i inventory/sample/inventory.ini all -m debug -a "var=hostvars[inventory_hostname]"`):**
|
||||||
|
<!-- We recommend using snippets services like https://gist.github.com/ etc. -->
|
||||||
|
|
||||||
|
**Command used to invoke ansible**:
|
||||||
|
|
||||||
|
|
||||||
|
**Output of ansible run**:
|
||||||
|
<!-- We recommend using snippets services like https://gist.github.com/ etc. -->
|
||||||
|
|
||||||
|
**Anything else do we need to know**:
|
||||||
|
<!-- By running scripts/collect-info.yaml you can get a lot of useful informations.
|
||||||
|
Script can be started by:
|
||||||
|
ansible-playbook -i <inventory_file_path> -u <ssh_user> -e ansible_ssh_user=<ssh_user> -b --become-user=root -e dir=`pwd` scripts/collect-info.yaml
|
||||||
|
(If you using CoreOS remember to add '-e ansible_python_interpreter=/opt/bin/python').
|
||||||
|
After running this command you can find logs in `pwd`/logs.tar.gz. You can even upload somewhere entire file and paste link here.-->
|
||||||
148
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
148
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
@@ -1,148 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug Report
|
|
||||||
description: Report a bug encountered while using Kubespray
|
|
||||||
labels: kind/bug
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Please, be ready for followup questions, and please respond in a timely
|
|
||||||
manner. If we can't reproduce a bug or think a feature already exists, we
|
|
||||||
might close your issue. If we're wrong, PLEASE feel free to reopen it and
|
|
||||||
explain why.
|
|
||||||
- type: textarea
|
|
||||||
id: problem
|
|
||||||
attributes:
|
|
||||||
label: What happened?
|
|
||||||
description: |
|
|
||||||
Please provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: expected
|
|
||||||
attributes:
|
|
||||||
label: What did you expect to happen?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: repro
|
|
||||||
attributes:
|
|
||||||
label: How can we reproduce it (as minimally and precisely as possible)?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: '### Environment'
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: os
|
|
||||||
attributes:
|
|
||||||
label: OS
|
|
||||||
options:
|
|
||||||
- 'RHEL 9'
|
|
||||||
- 'RHEL 8'
|
|
||||||
- 'Fedora 40'
|
|
||||||
- 'Ubuntu 24'
|
|
||||||
- 'Ubuntu 22'
|
|
||||||
- 'Ubuntu 20'
|
|
||||||
- 'Debian 12'
|
|
||||||
- 'Debian 11'
|
|
||||||
- 'Flatcar Container Linux'
|
|
||||||
- 'openSUSE Leap'
|
|
||||||
- 'openSUSE Tumbleweed'
|
|
||||||
- 'Oracle Linux 9'
|
|
||||||
- 'Oracle Linux 8'
|
|
||||||
- 'AlmaLinux 9'
|
|
||||||
- 'AlmaLinux 8'
|
|
||||||
- 'Rocky Linux 9'
|
|
||||||
- 'Rocky Linux 8'
|
|
||||||
- 'Amazon Linux 2'
|
|
||||||
- 'Kylin Linux Advanced Server V10'
|
|
||||||
- 'UOS Linux 20'
|
|
||||||
- 'openEuler 24'
|
|
||||||
- 'openEuler 22'
|
|
||||||
- 'openEuler 20'
|
|
||||||
- 'Other|Unsupported'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: ansible_version
|
|
||||||
attributes:
|
|
||||||
label: Version of Ansible
|
|
||||||
placeholder: 'ansible --version'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: python_version
|
|
||||||
attributes:
|
|
||||||
label: Version of Python
|
|
||||||
placeholder: 'python --version'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: kubespray_version
|
|
||||||
attributes:
|
|
||||||
label: Version of Kubespray (commit)
|
|
||||||
placeholder: 'git rev-parse --short HEAD'
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: network_plugin
|
|
||||||
attributes:
|
|
||||||
label: Network plugin used
|
|
||||||
options:
|
|
||||||
- calico
|
|
||||||
- cilium
|
|
||||||
- cni
|
|
||||||
- custom_cni
|
|
||||||
- flannel
|
|
||||||
- kube-ovn
|
|
||||||
- kube-router
|
|
||||||
- macvlan
|
|
||||||
- meta
|
|
||||||
- multus
|
|
||||||
- ovn4nfv
|
|
||||||
- weave
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: inventory
|
|
||||||
attributes:
|
|
||||||
label: Full inventory with variables
|
|
||||||
placeholder: 'ansible -i inventory/sample/inventory.ini all -m debug -a "var=hostvars[inventory_hostname]"'
|
|
||||||
description: We recommend using snippets services like https://gist.github.com/ etc.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: ansible_command
|
|
||||||
attributes:
|
|
||||||
label: Command used to invoke ansible
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: ansible_output
|
|
||||||
attributes:
|
|
||||||
label: Output of ansible run
|
|
||||||
description: We recommend using snippets services like https://gist.github.com/ etc.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: anything_else
|
|
||||||
attributes:
|
|
||||||
label: Anything else we need to know
|
|
||||||
description: |
|
|
||||||
By running scripts/collect-info.yaml you can get a lot of useful informations.
|
|
||||||
Script can be started by:
|
|
||||||
ansible-playbook -i <inventory_file_path> -u <ssh_user> -e ansible_ssh_user=<ssh_user> -b --become-user=root -e dir=`pwd` scripts/collect-info.yaml
|
|
||||||
(If you using CoreOS remember to add '-e ansible_python_interpreter=/opt/bin/python').
|
|
||||||
After running this command you can find logs in `pwd`/logs.tar.gz. You can even upload somewhere entire file and paste link here
|
|
||||||
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Support Request
|
|
||||||
url: https://kubernetes.slack.com/channels/kubespray
|
|
||||||
about: Support request or question relating to Kubernetes
|
|
||||||
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: Enhancement Request
|
||||||
|
about: Suggest an enhancement to the Kubespray project
|
||||||
|
labels: kind/feature
|
||||||
|
|
||||||
|
---
|
||||||
|
<!-- Please only use this template for submitting enhancement requests -->
|
||||||
|
|
||||||
|
**What would you like to be added**:
|
||||||
|
|
||||||
|
**Why is this needed**:
|
||||||
20
.github/ISSUE_TEMPLATE/enhancement.yaml
vendored
20
.github/ISSUE_TEMPLATE/enhancement.yaml
vendored
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enhancement Request
|
|
||||||
description: Suggest an enhancement to the Kubespray project
|
|
||||||
labels: kind/feature
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: Please only use this template for submitting enhancement requests
|
|
||||||
- type: textarea
|
|
||||||
id: what
|
|
||||||
attributes:
|
|
||||||
label: What would you like to be added
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: why
|
|
||||||
attributes:
|
|
||||||
label: Why is this needed
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
20
.github/ISSUE_TEMPLATE/failing-test.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/failing-test.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Failing Test
|
||||||
|
about: Report test failures in Kubespray CI jobs
|
||||||
|
labels: kind/failing-test
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Please only use this template for submitting reports about failing tests in Kubespray CI jobs -->
|
||||||
|
|
||||||
|
**Which jobs are failing**:
|
||||||
|
|
||||||
|
**Which test(s) are failing**:
|
||||||
|
|
||||||
|
**Since when has it been failing**:
|
||||||
|
|
||||||
|
**Testgrid link**:
|
||||||
|
|
||||||
|
**Reason for failure**:
|
||||||
|
|
||||||
|
**Anything else we need to know**:
|
||||||
41
.github/ISSUE_TEMPLATE/failing-test.yaml
vendored
41
.github/ISSUE_TEMPLATE/failing-test.yaml
vendored
@@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
name: Failing Test
|
|
||||||
description: Report test failures in Kubespray CI jobs
|
|
||||||
labels: kind/failing-test
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: Please only use this template for submitting reports about failing tests in Kubespray CI jobs
|
|
||||||
- type: textarea
|
|
||||||
id: failing_jobs
|
|
||||||
attributes:
|
|
||||||
label: Which jobs are failing ?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: failing_tests
|
|
||||||
attributes:
|
|
||||||
label: Which tests are failing ?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: since_when
|
|
||||||
attributes:
|
|
||||||
label: Since when has it been failing ?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: failure_reason
|
|
||||||
attributes:
|
|
||||||
label: Reason for failure
|
|
||||||
description: If you don't know and have no guess, just put "Unknown"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: anything_else
|
|
||||||
attributes:
|
|
||||||
label: Anything else we need to know
|
|
||||||
18
.github/ISSUE_TEMPLATE/support.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/support.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
name: Support Request
|
||||||
|
about: Support request or question relating to Kubespray
|
||||||
|
labels: kind/support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
STOP -- PLEASE READ!
|
||||||
|
|
||||||
|
GitHub is not the right place for support requests.
|
||||||
|
|
||||||
|
If you're looking for help, check [Stack Overflow](https://stackoverflow.com/questions/tagged/kubespray) and the [troubleshooting guide](https://kubernetes.io/docs/tasks/debug-application-cluster/troubleshooting/).
|
||||||
|
|
||||||
|
You can also post your question on the [Kubernetes Slack](http://slack.k8s.io/) or the [Discuss Kubernetes](https://discuss.kubernetes.io/) forum.
|
||||||
|
|
||||||
|
If the matter is security related, please disclose it privately via https://kubernetes.io/security/.
|
||||||
|
-->
|
||||||
14
.github/dependabot.yml
vendored
14
.github/dependabot.yml
vendored
@@ -1,14 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "pip"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
labels:
|
|
||||||
- dependencies
|
|
||||||
- release-note-none
|
|
||||||
groups:
|
|
||||||
molecule:
|
|
||||||
patterns:
|
|
||||||
- molecule
|
|
||||||
- molecule-plugins*
|
|
||||||
32
.github/workflows/auto-label-os.yml
vendored
32
.github/workflows/auto-label-os.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Issue labeler
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
label-component:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Parse issue form
|
|
||||||
uses: stefanbuck/github-issue-parser@v3
|
|
||||||
id: issue-parser
|
|
||||||
with:
|
|
||||||
template-path: .github/ISSUE_TEMPLATE/bug-report.yaml
|
|
||||||
|
|
||||||
- name: Set labels based on OS field
|
|
||||||
uses: redhat-plumbers-in-action/advanced-issue-labeler@v2
|
|
||||||
with:
|
|
||||||
issue-form: ${{ steps.issue-parser.outputs.jsonString }}
|
|
||||||
section: os
|
|
||||||
block-list: |
|
|
||||||
None
|
|
||||||
Other
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,8 +3,6 @@
|
|||||||
**/vagrant_ansible_inventory
|
**/vagrant_ansible_inventory
|
||||||
*.iml
|
*.iml
|
||||||
temp
|
temp
|
||||||
contrib/offline/container-images
|
|
||||||
contrib/offline/container-images.tar.gz
|
|
||||||
contrib/offline/offline-files
|
contrib/offline/offline-files
|
||||||
contrib/offline/offline-files.tar.gz
|
contrib/offline/offline-files.tar.gz
|
||||||
.idea
|
.idea
|
||||||
|
|||||||
@@ -1,34 +1,37 @@
|
|||||||
---
|
---
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
- test
|
- unit-tests
|
||||||
- deploy-part1
|
- deploy-part1
|
||||||
- deploy-extended
|
- moderator
|
||||||
|
- deploy-part2
|
||||||
|
- deploy-part3
|
||||||
|
- deploy-special
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
|
KUBESPRAY_VERSION: v2.22.1
|
||||||
FAILFASTCI_NAMESPACE: 'kargo-ci'
|
FAILFASTCI_NAMESPACE: 'kargo-ci'
|
||||||
GITLAB_REPOSITORY: 'kargo-ci/kubernetes-sigs-kubespray'
|
GITLAB_REPOSITORY: 'kargo-ci/kubernetes-sigs-kubespray'
|
||||||
GIT_CONFIG_COUNT: 2
|
|
||||||
GIT_CONFIG_KEY_0: user.email
|
|
||||||
GIT_CONFIG_VALUE_0: "ci@kubespray.io"
|
|
||||||
GIT_CONFIG_KEY_1: user.name
|
|
||||||
GIT_CONFIG_VALUE_1: "Kubespray CI"
|
|
||||||
ANSIBLE_FORCE_COLOR: "true"
|
ANSIBLE_FORCE_COLOR: "true"
|
||||||
MAGIC: "ci check this"
|
MAGIC: "ci check this"
|
||||||
|
TEST_ID: "$CI_PIPELINE_ID-$CI_JOB_ID"
|
||||||
|
CI_TEST_VARS: "./tests/files/${CI_JOB_NAME}.yml"
|
||||||
|
CI_TEST_REGISTRY_MIRROR: "./tests/common/_docker_hub_registry_mirror.yml"
|
||||||
|
CI_TEST_SETTING: "./tests/common/_kubespray_test_settings.yml"
|
||||||
GS_ACCESS_KEY_ID: $GS_KEY
|
GS_ACCESS_KEY_ID: $GS_KEY
|
||||||
GS_SECRET_ACCESS_KEY: $GS_SECRET
|
GS_SECRET_ACCESS_KEY: $GS_SECRET
|
||||||
CONTAINER_ENGINE: docker
|
CONTAINER_ENGINE: docker
|
||||||
|
SSH_USER: root
|
||||||
GCE_PREEMPTIBLE: "false"
|
GCE_PREEMPTIBLE: "false"
|
||||||
ANSIBLE_KEEP_REMOTE_FILES: "1"
|
ANSIBLE_KEEP_REMOTE_FILES: "1"
|
||||||
ANSIBLE_CONFIG: ./tests/ansible.cfg
|
ANSIBLE_CONFIG: ./tests/ansible.cfg
|
||||||
ANSIBLE_REMOTE_USER: kubespray
|
ANSIBLE_INVENTORY: ./inventory/sample/${CI_JOB_NAME}-${BUILD_NUMBER}.ini
|
||||||
ANSIBLE_PRIVATE_KEY_FILE: /tmp/id_rsa
|
IDEMPOT_CHECK: "false"
|
||||||
ANSIBLE_INVENTORY: /tmp/inventory
|
|
||||||
RESET_CHECK: "false"
|
RESET_CHECK: "false"
|
||||||
REMOVE_NODE_CHECK: "false"
|
REMOVE_NODE_CHECK: "false"
|
||||||
UPGRADE_TEST: "false"
|
UPGRADE_TEST: "false"
|
||||||
MITOGEN_ENABLE: "false"
|
MITOGEN_ENABLE: "false"
|
||||||
ANSIBLE_VERBOSITY: 2
|
ANSIBLE_LOG_LEVEL: "-vv"
|
||||||
RECOVER_CONTROL_PLANE_TEST: "false"
|
RECOVER_CONTROL_PLANE_TEST: "false"
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:]:kube_control_plane[1:]"
|
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:]:kube_control_plane[1:]"
|
||||||
TERRAFORM_VERSION: 1.3.7
|
TERRAFORM_VERSION: 1.3.7
|
||||||
@@ -40,27 +43,16 @@ before_script:
|
|||||||
|
|
||||||
.job: &job
|
.job: &job
|
||||||
tags:
|
tags:
|
||||||
- ffci
|
- packet
|
||||||
image: $PIPELINE_IMAGE
|
image: $PIPELINE_IMAGE
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
- cluster-dump/
|
- cluster-dump/
|
||||||
needs:
|
|
||||||
- pipeline-image
|
|
||||||
variables:
|
|
||||||
ANSIBLE_STDOUT_CALLBACK: "debug"
|
|
||||||
|
|
||||||
.job-moderated:
|
|
||||||
extends: .job
|
|
||||||
needs:
|
|
||||||
- pipeline-image
|
|
||||||
- ci-not-authorized
|
|
||||||
- pre-commit # lint
|
|
||||||
- vagrant-validate # lint
|
|
||||||
|
|
||||||
.testcases: &testcases
|
.testcases: &testcases
|
||||||
extends: .job-moderated
|
<<: *job
|
||||||
|
retry: 1
|
||||||
interruptible: true
|
interruptible: true
|
||||||
before_script:
|
before_script:
|
||||||
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
||||||
@@ -69,38 +61,23 @@ before_script:
|
|||||||
script:
|
script:
|
||||||
- ./tests/scripts/testcases_run.sh
|
- ./tests/scripts/testcases_run.sh
|
||||||
after_script:
|
after_script:
|
||||||
- ./tests/scripts/testcases_cleanup.sh
|
- chronic ./tests/scripts/testcases_cleanup.sh
|
||||||
|
|
||||||
# For failfast, at least 1 job must be defined in .gitlab-ci.yml
|
# For failfast, at least 1 job must be defined in .gitlab-ci.yml
|
||||||
# Premoderated with manual actions
|
# Premoderated with manual actions
|
||||||
ci-not-authorized:
|
ci-authorized:
|
||||||
stage: build
|
extends: .job
|
||||||
before_script: []
|
stage: moderator
|
||||||
after_script: []
|
|
||||||
rules:
|
|
||||||
# LGTM or ok-to-test labels
|
|
||||||
- if: $PR_LABELS =~ /.*,(lgtm|approved|ok-to-test).*|^(lgtm|approved|ok-to-test).*/i
|
|
||||||
variables:
|
|
||||||
CI_OK_TO_TEST: '0'
|
|
||||||
when: always
|
|
||||||
- if: $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "trigger"
|
|
||||||
variables:
|
|
||||||
CI_OK_TO_TEST: '0'
|
|
||||||
- if: $CI_COMMIT_BRANCH == "master"
|
|
||||||
variables:
|
|
||||||
CI_OK_TO_TEST: '0'
|
|
||||||
- when: always
|
|
||||||
variables:
|
|
||||||
CI_OK_TO_TEST: '1'
|
|
||||||
script:
|
script:
|
||||||
- exit $CI_OK_TO_TEST
|
- /bin/sh scripts/premoderator.sh
|
||||||
tags:
|
except: ['triggers', 'master']
|
||||||
- ffci
|
# Disable ci moderator
|
||||||
needs: []
|
only: []
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- .gitlab-ci/build.yml
|
- .gitlab-ci/build.yml
|
||||||
- .gitlab-ci/lint.yml
|
- .gitlab-ci/lint.yml
|
||||||
|
- .gitlab-ci/shellcheck.yml
|
||||||
- .gitlab-ci/terraform.yml
|
- .gitlab-ci/terraform.yml
|
||||||
- .gitlab-ci/packet.yml
|
- .gitlab-ci/packet.yml
|
||||||
- .gitlab-ci/vagrant.yml
|
- .gitlab-ci/vagrant.yml
|
||||||
|
|||||||
@@ -1,33 +1,40 @@
|
|||||||
---
|
---
|
||||||
.build-container:
|
.build:
|
||||||
cache:
|
|
||||||
key: $CI_COMMIT_REF_SLUG
|
|
||||||
paths:
|
|
||||||
- image-cache
|
|
||||||
tags:
|
|
||||||
- ffci
|
|
||||||
stage: build
|
stage: build
|
||||||
image:
|
image:
|
||||||
name: gcr.io/kaniko-project/executor:debug
|
name: moby/buildkit:rootless
|
||||||
entrypoint: ['']
|
entrypoint: [""]
|
||||||
variables:
|
variables:
|
||||||
TAG: $CI_COMMIT_SHORT_SHA
|
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
|
||||||
PROJECT_DIR: $CI_PROJECT_DIR
|
|
||||||
DOCKERFILE: Dockerfile
|
|
||||||
GODEBUG: "http2client=0"
|
|
||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
|
- mkdir ~/.docker
|
||||||
script:
|
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
|
||||||
- /kaniko/executor --cache=true
|
|
||||||
--cache-dir=image-cache
|
|
||||||
--context $PROJECT_DIR
|
|
||||||
--dockerfile $PROJECT_DIR/$DOCKERFILE
|
|
||||||
--label 'git-branch'=$CI_COMMIT_REF_SLUG
|
|
||||||
--label 'git-tag=$CI_COMMIT_TAG'
|
|
||||||
--destination $PIPELINE_IMAGE
|
|
||||||
--log-timestamp=true
|
|
||||||
|
|
||||||
pipeline-image:
|
pipeline image:
|
||||||
extends: .build-container
|
extends: .build
|
||||||
variables:
|
script:
|
||||||
DOCKERFILE: pipeline.Dockerfile
|
- |
|
||||||
|
buildctl-daemonless.sh build \
|
||||||
|
--frontend=dockerfile.v0 \
|
||||||
|
--local context=. \
|
||||||
|
--local dockerfile=. \
|
||||||
|
--opt filename=./pipeline.Dockerfile \
|
||||||
|
--output type=image,name=$PIPELINE_IMAGE,push=true \
|
||||||
|
--import-cache type=registry,ref=$CI_REGISTRY_IMAGE/pipeline:cache
|
||||||
|
rules:
|
||||||
|
- if: '$CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH'
|
||||||
|
|
||||||
|
pipeline image and build cache:
|
||||||
|
extends: .build
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
buildctl-daemonless.sh build \
|
||||||
|
--frontend=dockerfile.v0 \
|
||||||
|
--local context=. \
|
||||||
|
--local dockerfile=. \
|
||||||
|
--opt filename=./pipeline.Dockerfile \
|
||||||
|
--output type=image,name=$PIPELINE_IMAGE,push=true \
|
||||||
|
--import-cache type=registry,ref=$CI_REGISTRY_IMAGE/pipeline:cache \
|
||||||
|
--export-cache type=registry,ref=$CI_REGISTRY_IMAGE/pipeline:cache,mode=max
|
||||||
|
rules:
|
||||||
|
- if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
|
||||||
|
|||||||
@@ -1,26 +1,110 @@
|
|||||||
---
|
---
|
||||||
pre-commit:
|
yamllint:
|
||||||
stage: test
|
extends: .job
|
||||||
tags:
|
stage: unit-tests
|
||||||
- ffci
|
tags: [light]
|
||||||
image: 'ghcr.io/pre-commit-ci/runner-image@sha256:fe01a6ec51b298412990b88627c3973b1146c7304f930f469bafa29ba60bcde9'
|
|
||||||
variables:
|
variables:
|
||||||
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
LANG: C.UTF-8
|
||||||
script:
|
script:
|
||||||
- pre-commit run --all-files --show-diff-on-failure
|
- yamllint --strict .
|
||||||
cache:
|
except: ['triggers', 'master']
|
||||||
key: pre-commit-2
|
|
||||||
paths:
|
|
||||||
- ${PRE_COMMIT_HOME}
|
|
||||||
when: 'always'
|
|
||||||
needs: []
|
|
||||||
|
|
||||||
vagrant-validate:
|
vagrant-validate:
|
||||||
extends: .job
|
extends: .job
|
||||||
stage: test
|
stage: unit-tests
|
||||||
tags: [ffci]
|
tags: [light]
|
||||||
variables:
|
variables:
|
||||||
VAGRANT_VERSION: 2.3.7
|
VAGRANT_VERSION: 2.3.4
|
||||||
script:
|
script:
|
||||||
- ./tests/scripts/vagrant-validate.sh
|
- ./tests/scripts/vagrant-validate.sh
|
||||||
except: ['triggers', 'master']
|
except: ['triggers', 'master']
|
||||||
|
|
||||||
|
ansible-lint:
|
||||||
|
extends: .job
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
script:
|
||||||
|
- ansible-lint -v
|
||||||
|
except: ['triggers', 'master']
|
||||||
|
|
||||||
|
syntax-check:
|
||||||
|
extends: .job
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
variables:
|
||||||
|
ANSIBLE_INVENTORY: inventory/local-tests.cfg
|
||||||
|
ANSIBLE_REMOTE_USER: root
|
||||||
|
ANSIBLE_BECOME: "true"
|
||||||
|
ANSIBLE_BECOME_USER: root
|
||||||
|
ANSIBLE_VERBOSITY: "3"
|
||||||
|
script:
|
||||||
|
- ansible-playbook --syntax-check cluster.yml
|
||||||
|
- ansible-playbook --syntax-check playbooks/cluster.yml
|
||||||
|
- ansible-playbook --syntax-check upgrade-cluster.yml
|
||||||
|
- ansible-playbook --syntax-check playbooks/upgrade_cluster.yml
|
||||||
|
- ansible-playbook --syntax-check reset.yml
|
||||||
|
- ansible-playbook --syntax-check playbooks/reset.yml
|
||||||
|
- ansible-playbook --syntax-check extra_playbooks/upgrade-only-k8s.yml
|
||||||
|
except: ['triggers', 'master']
|
||||||
|
|
||||||
|
collection-build-install-sanity-check:
|
||||||
|
extends: .job
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
variables:
|
||||||
|
ANSIBLE_COLLECTIONS_PATH: "./ansible_collections"
|
||||||
|
script:
|
||||||
|
- ansible-galaxy collection build
|
||||||
|
- ansible-galaxy collection install kubernetes_sigs-kubespray-$(grep "^version:" galaxy.yml | awk '{print $2}').tar.gz
|
||||||
|
- ansible-galaxy collection list $(egrep -i '(name:\s+|namespace:\s+)' galaxy.yml | awk '{print $2}' | tr '\n' '.' | sed 's|\.$||g') | grep "^kubernetes_sigs.kubespray"
|
||||||
|
- test -f ansible_collections/kubernetes_sigs/kubespray/playbooks/cluster.yml
|
||||||
|
- test -f ansible_collections/kubernetes_sigs/kubespray/playbooks/reset.yml
|
||||||
|
except: ['triggers', 'master']
|
||||||
|
|
||||||
|
tox-inventory-builder:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
extends: .job
|
||||||
|
before_script:
|
||||||
|
- ./tests/scripts/rebase.sh
|
||||||
|
script:
|
||||||
|
- pip3 install tox
|
||||||
|
- cd contrib/inventory_builder && tox
|
||||||
|
except: ['triggers', 'master']
|
||||||
|
|
||||||
|
markdownlint:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
image: node
|
||||||
|
before_script:
|
||||||
|
- npm install -g markdownlint-cli@0.22.0
|
||||||
|
script:
|
||||||
|
- markdownlint $(find . -name '*.md' | grep -vF './.git') --ignore docs/_sidebar.md --ignore contrib/dind/README.md
|
||||||
|
|
||||||
|
check-readme-versions:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
image: python:3
|
||||||
|
script:
|
||||||
|
- tests/scripts/check_readme_versions.sh
|
||||||
|
|
||||||
|
check-galaxy-version:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
image: python:3
|
||||||
|
script:
|
||||||
|
- tests/scripts/check_galaxy_version.sh
|
||||||
|
|
||||||
|
check-typo:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
image: python:3
|
||||||
|
script:
|
||||||
|
- tests/scripts/check_typo.sh
|
||||||
|
|
||||||
|
ci-matrix:
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
image: python:3
|
||||||
|
script:
|
||||||
|
- tests/scripts/md-table/test.sh
|
||||||
|
|||||||
@@ -1,56 +1,83 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
.molecule:
|
.molecule:
|
||||||
tags: [ffci]
|
tags: [c3.small.x86]
|
||||||
only: [/^pr-.*$/]
|
only: [/^pr-.*$/]
|
||||||
except: ['triggers']
|
except: ['triggers']
|
||||||
stage: deploy-part1
|
|
||||||
image: $PIPELINE_IMAGE
|
image: $PIPELINE_IMAGE
|
||||||
needs:
|
services: []
|
||||||
- pipeline-image
|
stage: deploy-part1
|
||||||
# - ci-not-authorized
|
|
||||||
before_script:
|
before_script:
|
||||||
- ./tests/scripts/rebase.sh
|
- tests/scripts/rebase.sh
|
||||||
|
- ./tests/scripts/vagrant_clean.sh
|
||||||
script:
|
script:
|
||||||
- ./tests/scripts/molecule_run.sh
|
- ./tests/scripts/molecule_run.sh
|
||||||
after_script:
|
after_script:
|
||||||
- ./tests/scripts/molecule_logs.sh
|
- chronic ./tests/scripts/molecule_logs.sh
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
- molecule_logs/
|
- molecule_logs/
|
||||||
|
|
||||||
molecule:
|
|
||||||
extends: .molecule
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i $ROLE
|
|
||||||
parallel:
|
|
||||||
matrix:
|
|
||||||
- ROLE:
|
|
||||||
- container-engine/cri-dockerd
|
|
||||||
- container-engine/containerd
|
|
||||||
- container-engine/cri-o
|
|
||||||
- adduser
|
|
||||||
- bastion-ssh-config
|
|
||||||
- bootstrap-os
|
|
||||||
|
|
||||||
# CI template for periodic CI jobs
|
# CI template for periodic CI jobs
|
||||||
# Enabled when PERIODIC_CI_ENABLED var is set
|
# Enabled when PERIODIC_CI_ENABLED var is set
|
||||||
molecule_full:
|
.molecule_periodic:
|
||||||
only:
|
only:
|
||||||
variables:
|
variables:
|
||||||
- $PERIODIC_CI_ENABLED
|
- $PERIODIC_CI_ENABLED
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
extends: molecule
|
extends: .molecule
|
||||||
parallel:
|
|
||||||
matrix:
|
molecule_full:
|
||||||
- ROLE:
|
extends: .molecule_periodic
|
||||||
- container-engine/cri-dockerd
|
|
||||||
- container-engine/containerd
|
molecule_no_container_engines:
|
||||||
- container-engine/cri-o
|
extends: .molecule
|
||||||
- adduser
|
script:
|
||||||
- bastion-ssh-config
|
- ./tests/scripts/molecule_run.sh -e container-engine
|
||||||
- bootstrap-os
|
when: on_success
|
||||||
# FIXME : tests below are perma-failing
|
|
||||||
- container-engine/kata-containers
|
molecule_docker:
|
||||||
- container-engine/gvisor
|
extends: .molecule
|
||||||
- container-engine/youki
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/cri-dockerd
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
molecule_containerd:
|
||||||
|
extends: .molecule
|
||||||
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/containerd
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
molecule_cri-o:
|
||||||
|
extends: .molecule
|
||||||
|
stage: deploy-part2
|
||||||
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/cri-o
|
||||||
|
allow_failure: true
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
# Stage 3 container engines don't get as much attention so allow them to fail
|
||||||
|
molecule_kata:
|
||||||
|
extends: .molecule
|
||||||
|
stage: deploy-part3
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/kata-containers
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
molecule_gvisor:
|
||||||
|
extends: .molecule
|
||||||
|
stage: deploy-part3
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/gvisor
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
molecule_youki:
|
||||||
|
extends: .molecule
|
||||||
|
stage: deploy-part3
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- ./tests/scripts/molecule_run.sh -i container-engine/youki
|
||||||
|
when: on_success
|
||||||
|
|||||||
@@ -6,56 +6,14 @@
|
|||||||
CI_PLATFORM: packet
|
CI_PLATFORM: packet
|
||||||
SSH_USER: kubespray
|
SSH_USER: kubespray
|
||||||
tags:
|
tags:
|
||||||
- ffci
|
- packet
|
||||||
needs:
|
except: [triggers]
|
||||||
- pipeline-image
|
|
||||||
- ci-not-authorized
|
|
||||||
|
|
||||||
# CI template for PRs
|
# CI template for PRs
|
||||||
.packet_pr:
|
.packet_pr:
|
||||||
stage: deploy-part1
|
only: [/^pr-.*$/]
|
||||||
rules:
|
|
||||||
- if: $PR_LABELS =~ /.*ci-short.*/
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: $CI_COMMIT_BRANCH =~ /^pr-.*$/
|
|
||||||
when: on_success
|
|
||||||
- when: manual
|
|
||||||
allow_failure: true
|
|
||||||
extends: .packet
|
extends: .packet
|
||||||
|
|
||||||
## Uncomment this to have multiple stages
|
|
||||||
# needs:
|
|
||||||
# - packet_ubuntu20-calico-all-in-one
|
|
||||||
|
|
||||||
.packet_pr_short:
|
|
||||||
stage: deploy-part1
|
|
||||||
extends: .packet
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_BRANCH =~ /^pr-.*$/
|
|
||||||
when: on_success
|
|
||||||
- when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
.packet_pr_manual:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-extended
|
|
||||||
rules:
|
|
||||||
- if: $PR_LABELS =~ /.*ci-full.*/
|
|
||||||
when: on_success
|
|
||||||
# Else run as manual
|
|
||||||
- when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
.packet_pr_extended:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-extended
|
|
||||||
rules:
|
|
||||||
- if: $PR_LABELS =~ /.*(ci-extended|ci-full).*/
|
|
||||||
when: on_success
|
|
||||||
- when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
# CI template for periodic CI jobs
|
# CI template for periodic CI jobs
|
||||||
# Enabled when PERIODIC_CI_ENABLED var is set
|
# Enabled when PERIODIC_CI_ENABLED var is set
|
||||||
.packet_periodic:
|
.packet_periodic:
|
||||||
@@ -65,193 +23,305 @@
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
extends: .packet
|
extends: .packet
|
||||||
|
|
||||||
# The ubuntu20-calico-all-in-one jobs are meant as early stages to prevent running the full CI if something is horribly broken
|
packet_cleanup_old:
|
||||||
packet_ubuntu20-calico-all-in-one:
|
|
||||||
stage: deploy-part1
|
stage: deploy-part1
|
||||||
extends: .packet_pr_short
|
extends: .packet_periodic
|
||||||
|
script:
|
||||||
|
- cd tests
|
||||||
|
- make cleanup-packet
|
||||||
|
after_script: []
|
||||||
|
|
||||||
|
# The ubuntu20-calico-aio jobs are meant as early stages to prevent running the full CI if something is horribly broken
|
||||||
|
packet_ubuntu20-calico-aio:
|
||||||
|
stage: deploy-part1
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
RESET_CHECK: "true"
|
RESET_CHECK: "true"
|
||||||
|
|
||||||
# ### PR JOBS PART2
|
# ### PR JOBS PART2
|
||||||
|
|
||||||
|
packet_ubuntu20-aio-docker:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_ubuntu20-calico-aio-hardening:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_ubuntu22-aio-docker:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_ubuntu22-calico-aio:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_centos7-flannel-addons-ha:
|
||||||
|
extends: .packet_pr
|
||||||
|
stage: deploy-part2
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_almalinux8-crio:
|
||||||
|
extends: .packet_pr
|
||||||
|
stage: deploy-part2
|
||||||
|
when: on_success
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
packet_ubuntu20-crio:
|
packet_ubuntu20-crio:
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_ubuntu22-calico-all-in-one:
|
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
stage: deploy-part2
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_ubuntu22-calico-all-in-one-upgrade:
|
packet_fedora37-crio:
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
variables:
|
stage: deploy-part2
|
||||||
UPGRADE_TEST: graceful
|
when: manual
|
||||||
|
|
||||||
packet_ubuntu24-calico-etcd-datastore:
|
packet_ubuntu20-flannel-ha:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_almalinux9-crio:
|
packet_debian10-cilium-svc-proxy:
|
||||||
extends: .packet_pr
|
stage: deploy-part2
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_almalinux9-kube-ovn:
|
packet_debian10-calico:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_debian11-calico-collection:
|
packet_debian10-docker:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_debian11-macvlan:
|
packet_debian11-calico:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_debian11-docker:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_debian12-calico:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_debian12-docker:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_debian12-cilium:
|
packet_debian12-cilium:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_centos7-calico-ha-once-localhost:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
# This will instruct Docker not to start over TLS.
|
||||||
|
DOCKER_TLS_CERTDIR: ""
|
||||||
|
services:
|
||||||
|
- docker:19.03.9-dind
|
||||||
|
|
||||||
|
packet_almalinux8-kube-ovn:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_almalinux8-calico:
|
packet_almalinux8-calico:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_rockylinux8-calico:
|
packet_rockylinux8-calico:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_rockylinux9-calico:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
packet_rockylinux9-cilium:
|
packet_rockylinux9-cilium:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
RESET_CHECK: "true"
|
RESET_CHECK: "true"
|
||||||
|
|
||||||
# Need an update of the container image to use schema v2
|
packet_almalinux8-docker:
|
||||||
# update: quay.io/kubespray/vm-amazon-linux-2:latest
|
stage: deploy-part2
|
||||||
packet_amazon-linux-2-all-in-one:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
rules:
|
|
||||||
- when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
packet_opensuse15-6-calico:
|
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_fedora38-docker-weave:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
packet_opensuse-docker-cilium:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
# ### MANUAL JOBS
|
||||||
|
|
||||||
|
packet_ubuntu20-docker-weave-sep:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_ubuntu20-cilium-sep:
|
packet_ubuntu20-cilium-sep:
|
||||||
|
stage: deploy-special
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_openeuler24-calico:
|
packet_ubuntu20-flannel-ha-once:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_ubuntu20-calico-all-in-one-hardening:
|
# Calico HA eBPF
|
||||||
|
packet_almalinux8-calico-ha-ebpf:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .packet_pr
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
## Extended
|
packet_debian10-macvlan:
|
||||||
packet_debian11-docker:
|
stage: deploy-part2
|
||||||
extends: .packet_pr_extended
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_debian12-docker:
|
packet_centos7-calico-ha:
|
||||||
extends: .packet_pr_extended
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_debian12-calico:
|
packet_centos7-multus-calico:
|
||||||
extends: .packet_pr_extended
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
packet_almalinux9-calico-remove-node:
|
packet_fedora38-docker-calico:
|
||||||
extends: .packet_pr_extended
|
stage: deploy-part2
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
RESET_CHECK: "true"
|
||||||
|
|
||||||
|
packet_fedora37-calico-selinux:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_fedora37-calico-swap-selinux:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
packet_amazon-linux-2-aio:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
packet_almalinux8-calico-nodelocaldns-secondary:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
packet_fedora38-kube-ovn:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
packet_debian11-custom-cni:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
packet_debian11-kubelet-csr-approver:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
# ### PR JOBS PART3
|
||||||
|
# Long jobs (45min+)
|
||||||
|
|
||||||
|
packet_centos7-weave-upgrade-ha:
|
||||||
|
stage: deploy-part3
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
UPGRADE_TEST: basic
|
||||||
|
|
||||||
|
packet_ubuntu20-calico-etcd-kubeadm-upgrade-ha:
|
||||||
|
stage: deploy-part3
|
||||||
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
UPGRADE_TEST: basic
|
||||||
|
|
||||||
|
# Calico HA Wireguard
|
||||||
|
packet_ubuntu20-calico-ha-wireguard:
|
||||||
|
stage: deploy-part2
|
||||||
|
extends: .packet_pr
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
packet_debian11-calico-upgrade:
|
||||||
|
stage: deploy-part3
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
|
variables:
|
||||||
|
UPGRADE_TEST: graceful
|
||||||
|
|
||||||
|
packet_almalinux8-calico-remove-node:
|
||||||
|
stage: deploy-part3
|
||||||
|
extends: .packet_pr
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
REMOVE_NODE_CHECK: "true"
|
REMOVE_NODE_CHECK: "true"
|
||||||
REMOVE_NODE_NAME: "instance-3"
|
REMOVE_NODE_NAME: "instance-3"
|
||||||
|
|
||||||
packet_rockylinux9-calico:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_almalinux9-calico:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_almalinux9-docker:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_opensuse15-6-docker-cilium:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_ubuntu24-calico-all-in-one:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-etcd-kubeadm:
|
packet_ubuntu20-calico-etcd-kubeadm:
|
||||||
extends: .packet_pr_extended
|
stage: deploy-part3
|
||||||
|
extends: .packet_pr
|
||||||
packet_ubuntu24-all-in-one-docker:
|
when: on_success
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
packet_ubuntu22-all-in-one-docker:
|
|
||||||
extends: .packet_pr_extended
|
|
||||||
|
|
||||||
# ### MANUAL JOBS
|
|
||||||
packet_fedora39-crio:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_ubuntu20-flannel-ha:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_ubuntu20-all-in-one-docker:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_ubuntu20-flannel-ha-once:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_fedora39-calico-swap-selinux:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_almalinux9-calico-ha-ebpf:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_almalinux9-calico-nodelocaldns-secondary:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_debian11-custom-cni:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_debian11-kubelet-csr-approver:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_debian12-custom-cni-helm:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-ha-wireguard:
|
|
||||||
extends: .packet_pr_manual
|
|
||||||
|
|
||||||
# PERIODIC
|
|
||||||
packet_fedora40-docker-calico:
|
|
||||||
stage: deploy-extended
|
|
||||||
extends: .packet_periodic
|
|
||||||
variables:
|
|
||||||
RESET_CHECK: "true"
|
|
||||||
|
|
||||||
packet_fedora39-calico-selinux:
|
|
||||||
stage: deploy-extended
|
|
||||||
extends: .packet_periodic
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-etcd-kubeadm-upgrade-ha:
|
|
||||||
stage: deploy-extended
|
|
||||||
extends: .packet_periodic
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: basic
|
|
||||||
|
|
||||||
|
|
||||||
packet_debian11-calico-upgrade-once:
|
packet_debian11-calico-upgrade-once:
|
||||||
stage: deploy-extended
|
stage: deploy-part3
|
||||||
extends: .packet_periodic
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
UPGRADE_TEST: graceful
|
UPGRADE_TEST: graceful
|
||||||
|
|
||||||
packet_ubuntu20-calico-ha-recover:
|
packet_ubuntu20-calico-ha-recover:
|
||||||
stage: deploy-extended
|
stage: deploy-part3
|
||||||
extends: .packet_periodic
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
RECOVER_CONTROL_PLANE_TEST: "true"
|
RECOVER_CONTROL_PLANE_TEST: "true"
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:]:kube_control_plane[1:]"
|
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:]:kube_control_plane[1:]"
|
||||||
|
|
||||||
packet_ubuntu20-calico-ha-recover-noquorum:
|
packet_ubuntu20-calico-ha-recover-noquorum:
|
||||||
stage: deploy-extended
|
stage: deploy-part3
|
||||||
extends: .packet_periodic
|
extends: .packet_periodic
|
||||||
|
when: on_success
|
||||||
variables:
|
variables:
|
||||||
RECOVER_CONTROL_PLANE_TEST: "true"
|
RECOVER_CONTROL_PLANE_TEST: "true"
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[1:]:kube_control_plane[1:]"
|
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[1:]:kube_control_plane[1:]"
|
||||||
|
|
||||||
packet_debian11-calico-upgrade:
|
|
||||||
stage: deploy-extended
|
|
||||||
extends: .packet_periodic
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: graceful
|
|
||||||
|
|
||||||
packet_debian12-cilium-svc-proxy:
|
|
||||||
stage: deploy-extended
|
|
||||||
extends: .packet_periodic
|
|
||||||
|
|||||||
16
.gitlab-ci/shellcheck.yml
Normal file
16
.gitlab-ci/shellcheck.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
shellcheck:
|
||||||
|
extends: .job
|
||||||
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
|
variables:
|
||||||
|
SHELLCHECK_VERSION: v0.7.1
|
||||||
|
before_script:
|
||||||
|
- ./tests/scripts/rebase.sh
|
||||||
|
- curl --silent --location "https://github.com/koalaman/shellcheck/releases/download/"${SHELLCHECK_VERSION}"/shellcheck-"${SHELLCHECK_VERSION}".linux.x86_64.tar.xz" | tar -xJv
|
||||||
|
- cp shellcheck-"${SHELLCHECK_VERSION}"/shellcheck /usr/bin/
|
||||||
|
- shellcheck --version
|
||||||
|
script:
|
||||||
|
# Run shellcheck for all *.sh
|
||||||
|
- find . -name '*.sh' -not -path './.git/*' | xargs shellcheck --severity error
|
||||||
|
except: ['triggers', 'master']
|
||||||
@@ -2,10 +2,6 @@
|
|||||||
# Tests for contrib/terraform/
|
# Tests for contrib/terraform/
|
||||||
.terraform_install:
|
.terraform_install:
|
||||||
extends: .job
|
extends: .job
|
||||||
needs:
|
|
||||||
- ci-not-authorized
|
|
||||||
- pipeline-image
|
|
||||||
stage: deploy-part1
|
|
||||||
before_script:
|
before_script:
|
||||||
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
||||||
- ./tests/scripts/rebase.sh
|
- ./tests/scripts/rebase.sh
|
||||||
@@ -28,19 +24,17 @@
|
|||||||
|
|
||||||
.terraform_validate:
|
.terraform_validate:
|
||||||
extends: .terraform_install
|
extends: .terraform_install
|
||||||
tags: [ffci]
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
only: ['master', /^pr-.*$/]
|
only: ['master', /^pr-.*$/]
|
||||||
script:
|
script:
|
||||||
- terraform -chdir="contrib/terraform/$PROVIDER" validate
|
- terraform -chdir="contrib/terraform/$PROVIDER" validate
|
||||||
- terraform -chdir="contrib/terraform/$PROVIDER" fmt -check -diff
|
- terraform -chdir="contrib/terraform/$PROVIDER" fmt -check -diff
|
||||||
stage: test
|
|
||||||
needs:
|
|
||||||
- pipeline-image
|
|
||||||
|
|
||||||
.terraform_apply:
|
.terraform_apply:
|
||||||
extends: .terraform_install
|
extends: .terraform_install
|
||||||
tags: [ffci]
|
tags: [light]
|
||||||
stage: deploy-extended
|
stage: deploy-part3
|
||||||
when: manual
|
when: manual
|
||||||
only: [/^pr-.*$/]
|
only: [/^pr-.*$/]
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -57,7 +51,7 @@
|
|||||||
- tests/scripts/testcases_run.sh
|
- tests/scripts/testcases_run.sh
|
||||||
after_script:
|
after_script:
|
||||||
# Cleanup regardless of exit code
|
# Cleanup regardless of exit code
|
||||||
- ./tests/scripts/testcases_cleanup.sh
|
- chronic ./tests/scripts/testcases_cleanup.sh
|
||||||
|
|
||||||
tf-validate-openstack:
|
tf-validate-openstack:
|
||||||
extends: .terraform_validate
|
extends: .terraform_validate
|
||||||
@@ -152,7 +146,8 @@ tf-validate-nifcloud:
|
|||||||
TF_VAR_router_id: "ab95917c-41fb-4881-b507-3a6dfe9403df"
|
TF_VAR_router_id: "ab95917c-41fb-4881-b507-3a6dfe9403df"
|
||||||
|
|
||||||
tf-elastx_cleanup:
|
tf-elastx_cleanup:
|
||||||
tags: [ffci]
|
stage: unit-tests
|
||||||
|
tags: [light]
|
||||||
image: python
|
image: python
|
||||||
variables:
|
variables:
|
||||||
<<: *elastx_variables
|
<<: *elastx_variables
|
||||||
@@ -160,11 +155,10 @@ tf-elastx_cleanup:
|
|||||||
- pip install -r scripts/openstack-cleanup/requirements.txt
|
- pip install -r scripts/openstack-cleanup/requirements.txt
|
||||||
script:
|
script:
|
||||||
- ./scripts/openstack-cleanup/main.py
|
- ./scripts/openstack-cleanup/main.py
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
tf-elastx_ubuntu20-calico:
|
tf-elastx_ubuntu20-calico:
|
||||||
extends: .terraform_apply
|
extends: .terraform_apply
|
||||||
stage: deploy-part1
|
stage: deploy-part3
|
||||||
when: on_success
|
when: on_success
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
variables:
|
variables:
|
||||||
|
|||||||
@@ -1,81 +1,63 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
.vagrant:
|
.vagrant:
|
||||||
extends: .testcases
|
extends: .testcases
|
||||||
needs:
|
|
||||||
- ci-not-authorized
|
|
||||||
variables:
|
variables:
|
||||||
CI_PLATFORM: "vagrant"
|
CI_PLATFORM: "vagrant"
|
||||||
SSH_USER: "vagrant"
|
SSH_USER: "vagrant"
|
||||||
VAGRANT_DEFAULT_PROVIDER: "libvirt"
|
VAGRANT_DEFAULT_PROVIDER: "libvirt"
|
||||||
KUBESPRAY_VAGRANT_CONFIG: tests/files/${CI_JOB_NAME}.rb
|
KUBESPRAY_VAGRANT_CONFIG: tests/files/${CI_JOB_NAME}.rb
|
||||||
DOCKER_NAME: vagrant
|
tags: [c3.small.x86]
|
||||||
VAGRANT_ANSIBLE_TAGS: facts
|
only: [/^pr-.*$/]
|
||||||
VAGRANT_HOME: "$CI_PROJECT_DIR/.vagrant.d"
|
except: ['triggers']
|
||||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
image: $PIPELINE_IMAGE
|
||||||
tags: [ffci-vm-large]
|
|
||||||
# only: [/^pr-.*$/]
|
|
||||||
# except: ['triggers']
|
|
||||||
image: quay.io/kubespray/vm-kubespray-ci:v13
|
|
||||||
services: []
|
services: []
|
||||||
before_script:
|
before_script:
|
||||||
- echo $USER
|
|
||||||
- python3 -m venv citest
|
|
||||||
- source citest/bin/activate
|
|
||||||
- vagrant plugin expunge --reinstall --force --no-tty
|
|
||||||
- vagrant plugin install vagrant-libvirt
|
|
||||||
- pip install --no-compile --no-cache-dir pip -U
|
|
||||||
- pip install --no-compile --no-cache-dir -r $CI_PROJECT_DIR/requirements.txt
|
|
||||||
- pip install --no-compile --no-cache-dir -r $CI_PROJECT_DIR/tests/requirements.txt
|
|
||||||
- ./tests/scripts/vagrant_clean.sh
|
- ./tests/scripts/vagrant_clean.sh
|
||||||
script:
|
script:
|
||||||
- ./tests/scripts/testcases_run.sh
|
- ./tests/scripts/testcases_run.sh
|
||||||
cache:
|
after_script:
|
||||||
key: $CI_JOB_NAME_SLUG
|
- chronic ./tests/scripts/testcases_cleanup.sh
|
||||||
paths:
|
allow_failure: true
|
||||||
- .vagrant.d/boxes
|
|
||||||
- .cache/pip
|
|
||||||
policy: pull-push # TODO: change to "pull" when not on main
|
|
||||||
|
|
||||||
vagrant_ubuntu24-calico-dual-stack:
|
vagrant_ubuntu20-calico-dual-stack:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
rules:
|
when: on_success
|
||||||
- if: $PR_LABELS =~ /.*(ci-extended|ci-full).*/
|
|
||||||
when: on_success
|
|
||||||
allow_failure: false
|
|
||||||
|
|
||||||
vagrant_ubuntu24-calico-ipv6only-stack:
|
vagrant_ubuntu20-weave-medium:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
rules:
|
when: manual
|
||||||
- if: $PR_LABELS =~ /.*(ci-extended|ci-full).*/
|
|
||||||
when: on_success
|
|
||||||
allow_failure: false
|
|
||||||
|
|
||||||
vagrant_ubuntu20-flannel:
|
vagrant_ubuntu20-flannel:
|
||||||
stage: deploy-part1
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
when: on_success
|
when: on_success
|
||||||
allow_failure: false
|
allow_failure: false
|
||||||
|
|
||||||
vagrant_ubuntu20-flannel-collection:
|
vagrant_ubuntu20-flannel-collection:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
when: manual
|
when: on_success
|
||||||
|
|
||||||
vagrant_ubuntu20-kube-router-sep:
|
vagrant_ubuntu20-kube-router-sep:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
when: manual
|
when: manual
|
||||||
|
|
||||||
# Service proxy test fails connectivity testing
|
# Service proxy test fails connectivity testing
|
||||||
vagrant_ubuntu20-kube-router-svc-proxy:
|
vagrant_ubuntu20-kube-router-svc-proxy:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
when: manual
|
when: manual
|
||||||
|
|
||||||
vagrant_fedora39-kube-router:
|
vagrant_fedora37-kube-router:
|
||||||
stage: deploy-extended
|
stage: deploy-part2
|
||||||
|
extends: .vagrant
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
vagrant_centos7-kube-router:
|
||||||
|
stage: deploy-part2
|
||||||
extends: .vagrant
|
extends: .vagrant
|
||||||
when: manual
|
when: manual
|
||||||
# FIXME: this test if broken (perma-failing)
|
|
||||||
|
|||||||
3
.markdownlint.yaml
Normal file
3
.markdownlint.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
MD013: false
|
||||||
|
MD029: false
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
all
|
|
||||||
exclude_rule 'MD013'
|
|
||||||
exclude_rule 'MD029'
|
|
||||||
rule 'MD007', :indent => 2
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
repos:
|
repos:
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v3.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
@@ -15,96 +16,56 @@ repos:
|
|||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/adrienverge/yamllint.git
|
- repo: https://github.com/adrienverge/yamllint.git
|
||||||
rev: v1.35.1
|
rev: v1.27.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: yamllint
|
- id: yamllint
|
||||||
args: [--strict]
|
args: [--strict]
|
||||||
|
|
||||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
- repo: https://github.com/markdownlint/markdownlint
|
||||||
rev: v0.10.0.1
|
rev: v0.11.0
|
||||||
|
hooks:
|
||||||
|
- id: markdownlint
|
||||||
|
args: [ -r, "~MD013,~MD029" ]
|
||||||
|
exclude: "^.git"
|
||||||
|
|
||||||
|
- repo: https://github.com/jumanjihouse/pre-commit-hooks
|
||||||
|
rev: 3.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: shellcheck
|
- id: shellcheck
|
||||||
args: ["--severity=error"]
|
args: [ --severity, "error" ]
|
||||||
exclude: "^.git"
|
exclude: "^.git"
|
||||||
files: "\\.sh$"
|
files: "\\.sh$"
|
||||||
|
|
||||||
- repo: https://github.com/ansible/ansible-lint
|
|
||||||
rev: v25.1.1
|
|
||||||
hooks:
|
|
||||||
- id: ansible-lint
|
|
||||||
additional_dependencies:
|
|
||||||
- jmespath==1.0.1
|
|
||||||
- netaddr==1.3.0
|
|
||||||
- distlib
|
|
||||||
|
|
||||||
- repo: https://github.com/golangci/misspell
|
|
||||||
rev: v0.6.0
|
|
||||||
hooks:
|
|
||||||
- id: misspell
|
|
||||||
exclude: "OWNERS_ALIASES$"
|
|
||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
- id: collection-build-install
|
- id: ansible-lint
|
||||||
name: Build and install kubernetes-sigs.kubespray Ansible collection
|
name: ansible-lint
|
||||||
|
entry: ansible-lint -v
|
||||||
language: python
|
language: python
|
||||||
|
pass_filenames: false
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- ansible-core>=2.16.4
|
- .[community]
|
||||||
- distlib
|
|
||||||
entry: tests/scripts/collection-build-install.sh
|
- id: ansible-syntax-check
|
||||||
|
name: ansible-syntax-check
|
||||||
|
entry: env ANSIBLE_INVENTORY=inventory/local-tests.cfg ANSIBLE_REMOTE_USER=root ANSIBLE_BECOME="true" ANSIBLE_BECOME_USER=root ANSIBLE_VERBOSITY="3" ansible-playbook --syntax-check
|
||||||
|
language: python
|
||||||
|
files: "^cluster.yml|^upgrade-cluster.yml|^reset.yml|^extra_playbooks/upgrade-only-k8s.yml"
|
||||||
|
|
||||||
|
- id: tox-inventory-builder
|
||||||
|
name: tox-inventory-builder
|
||||||
|
entry: bash -c "cd contrib/inventory_builder && tox"
|
||||||
|
language: python
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: generate-docs-sidebar
|
- id: check-readme-versions
|
||||||
name: generate-docs-sidebar
|
name: check-readme-versions
|
||||||
entry: scripts/gen_docs_sidebar.sh
|
entry: tests/scripts/check_readme_versions.sh
|
||||||
language: script
|
language: script
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: ci-matrix
|
- id: ci-matrix
|
||||||
name: ci-matrix
|
name: ci-matrix
|
||||||
entry: tests/scripts/md-table/main.py
|
entry: tests/scripts/md-table/test.sh
|
||||||
language: python
|
language: script
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
additional_dependencies:
|
|
||||||
- jinja2
|
|
||||||
- pathlib
|
|
||||||
- pyaml
|
|
||||||
|
|
||||||
- id: check-galaxy-version
|
|
||||||
name: Verify correct version for galaxy.yml
|
|
||||||
entry: scripts/galaxy_version.py
|
|
||||||
language: python
|
|
||||||
pass_filenames: false
|
|
||||||
additional_dependencies:
|
|
||||||
- ruamel.yaml
|
|
||||||
|
|
||||||
- id: jinja-syntax-check
|
|
||||||
name: jinja-syntax-check
|
|
||||||
entry: tests/scripts/check-templates.py
|
|
||||||
language: python
|
|
||||||
types:
|
|
||||||
- jinja
|
|
||||||
additional_dependencies:
|
|
||||||
- jinja2
|
|
||||||
|
|
||||||
- id: propagate-ansible-variables
|
|
||||||
name: Update static files referencing default kubespray values
|
|
||||||
language: python
|
|
||||||
additional_dependencies:
|
|
||||||
- ansible-core>=2.16.4
|
|
||||||
entry: scripts/propagate_ansible_variables.yml
|
|
||||||
pass_filenames: false
|
|
||||||
|
|
||||||
- id: check-checksums-sorted
|
|
||||||
name: Check that our checksums are correctly sorted by version
|
|
||||||
entry: scripts/assert-sorted-checksums.yml
|
|
||||||
language: python
|
|
||||||
pass_filenames: false
|
|
||||||
additional_dependencies:
|
|
||||||
- ansible
|
|
||||||
|
|
||||||
- repo: https://github.com/markdownlint/markdownlint
|
|
||||||
rev: v0.12.0
|
|
||||||
hooks:
|
|
||||||
- id: markdownlint
|
|
||||||
exclude: "^.github|(^docs/_sidebar\\.md$)"
|
|
||||||
|
|||||||
11
.yamllint
11
.yamllint
@@ -3,10 +3,9 @@ extends: default
|
|||||||
|
|
||||||
ignore: |
|
ignore: |
|
||||||
.git/
|
.git/
|
||||||
.github/
|
|
||||||
# Generated file
|
# Generated file
|
||||||
tests/files/custom_cni/cilium.yaml
|
tests/files/custom_cni/cilium.yaml
|
||||||
# https://ansible.readthedocs.io/projects/lint/rules/yaml/
|
|
||||||
rules:
|
rules:
|
||||||
braces:
|
braces:
|
||||||
min-spaces-inside: 0
|
min-spaces-inside: 0
|
||||||
@@ -14,15 +13,9 @@ rules:
|
|||||||
brackets:
|
brackets:
|
||||||
min-spaces-inside: 0
|
min-spaces-inside: 0
|
||||||
max-spaces-inside: 1
|
max-spaces-inside: 1
|
||||||
comments:
|
|
||||||
min-spaces-from-content: 1
|
|
||||||
# https://github.com/adrienverge/yamllint/issues/384
|
|
||||||
comments-indentation: false
|
|
||||||
indentation:
|
indentation:
|
||||||
spaces: 2
|
spaces: 2
|
||||||
indent-sequences: consistent
|
indent-sequences: consistent
|
||||||
line-length: disable
|
line-length: disable
|
||||||
new-line-at-end-of-file: disable
|
new-line-at-end-of-file: disable
|
||||||
octal-values:
|
truthy: disable
|
||||||
forbid-implicit-octal: true # yamllint defaults to false
|
|
||||||
forbid-explicit-octal: true # yamllint defaults to false
|
|
||||||
|
|||||||
59
Dockerfile
59
Dockerfile
@@ -1,8 +1,5 @@
|
|||||||
# syntax=docker/dockerfile:1
|
|
||||||
|
|
||||||
# Use imutable image tags rather than mutable tags (like ubuntu:22.04)
|
# Use imutable image tags rather than mutable tags (like ubuntu:22.04)
|
||||||
FROM ubuntu:22.04@sha256:149d67e29f765f4db62aa52161009e99e389544e25a8f43c8c89d4a445a7ca37
|
FROM ubuntu:jammy-20230308
|
||||||
|
|
||||||
# Some tools like yamllint need this
|
# Some tools like yamllint need this
|
||||||
# Pip needs this as well at the moment to install ansible
|
# Pip needs this as well at the moment to install ansible
|
||||||
# (and potentially other packages)
|
# (and potentially other packages)
|
||||||
@@ -10,35 +7,7 @@ FROM ubuntu:22.04@sha256:149d67e29f765f4db62aa52161009e99e389544e25a8f43c8c89d4a
|
|||||||
ENV LANG=C.UTF-8 \
|
ENV LANG=C.UTF-8 \
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
PYTHONDONTWRITEBYTECODE=1
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
|
|
||||||
WORKDIR /kubespray
|
WORKDIR /kubespray
|
||||||
|
|
||||||
# hadolint ignore=DL3008
|
|
||||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|
||||||
apt-get update -q \
|
|
||||||
&& apt-get install -yq --no-install-recommends \
|
|
||||||
curl \
|
|
||||||
python3 \
|
|
||||||
python3-pip \
|
|
||||||
sshpass \
|
|
||||||
vim \
|
|
||||||
rsync \
|
|
||||||
openssh-client \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /var/log/*
|
|
||||||
|
|
||||||
RUN --mount=type=bind,source=requirements.txt,target=requirements.txt \
|
|
||||||
--mount=type=cache,sharing=locked,id=pipcache,mode=0777,target=/root/.cache/pip \
|
|
||||||
pip install --no-compile --no-cache-dir -r requirements.txt \
|
|
||||||
&& find /usr -type d -name '*__pycache__' -prune -exec rm -rf {} \;
|
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
||||||
|
|
||||||
RUN OS_ARCHITECTURE=$(dpkg --print-architecture) \
|
|
||||||
&& curl -L "https://dl.k8s.io/release/v1.32.3/bin/linux/${OS_ARCHITECTURE}/kubectl" -o /usr/local/bin/kubectl \
|
|
||||||
&& echo "$(curl -L "https://dl.k8s.io/release/v1.32.3/bin/linux/${OS_ARCHITECTURE}/kubectl.sha256")" /usr/local/bin/kubectl | sha256sum --check \
|
|
||||||
&& chmod a+x /usr/local/bin/kubectl
|
|
||||||
|
|
||||||
COPY *.yml ./
|
COPY *.yml ./
|
||||||
COPY *.cfg ./
|
COPY *.cfg ./
|
||||||
COPY roles ./roles
|
COPY roles ./roles
|
||||||
@@ -48,3 +17,29 @@ COPY library ./library
|
|||||||
COPY extra_playbooks ./extra_playbooks
|
COPY extra_playbooks ./extra_playbooks
|
||||||
COPY playbooks ./playbooks
|
COPY playbooks ./playbooks
|
||||||
COPY plugins ./plugins
|
COPY plugins ./plugins
|
||||||
|
|
||||||
|
RUN apt update -q \
|
||||||
|
&& apt install -yq --no-install-recommends \
|
||||||
|
curl \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
sshpass \
|
||||||
|
vim \
|
||||||
|
rsync \
|
||||||
|
openssh-client \
|
||||||
|
&& pip install --no-compile --no-cache-dir \
|
||||||
|
ansible==7.6.0 \
|
||||||
|
ansible-core==2.14.6 \
|
||||||
|
cryptography==41.0.1 \
|
||||||
|
jinja2==3.1.2 \
|
||||||
|
netaddr==0.8.0 \
|
||||||
|
jmespath==1.0.1 \
|
||||||
|
MarkupSafe==2.1.3 \
|
||||||
|
ruamel.yaml==0.17.21 \
|
||||||
|
passlib==1.7.4 \
|
||||||
|
&& KUBE_VERSION=$(sed -n 's/^kube_version: //p' roles/kubespray-defaults/defaults/main.yaml) \
|
||||||
|
&& curl -L https://dl.k8s.io/release/$KUBE_VERSION/bin/linux/$(dpkg --print-architecture)/kubectl -o /usr/local/bin/kubectl \
|
||||||
|
&& echo $(curl -L https://dl.k8s.io/release/$KUBE_VERSION/bin/linux/$(dpkg --print-architecture)/kubectl.sha256) /usr/local/bin/kubectl | sha256sum --check \
|
||||||
|
&& chmod a+x /usr/local/bin/kubectl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/log/* \
|
||||||
|
&& find /usr -type d -name '*__pycache__' -prune -exec rm -rf {} \;
|
||||||
|
|||||||
7
Makefile
Normal file
7
Makefile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mitogen:
|
||||||
|
@echo Mitogen support is deprecated.
|
||||||
|
@echo Please run the following command manually:
|
||||||
|
@echo ansible-playbook -c local mitogen.yml -vv
|
||||||
|
clean:
|
||||||
|
rm -rf dist/
|
||||||
|
rm *.retry
|
||||||
@@ -1,26 +1,31 @@
|
|||||||
aliases:
|
aliases:
|
||||||
kubespray-approvers:
|
kubespray-approvers:
|
||||||
- cristicalin
|
|
||||||
- floryut
|
|
||||||
- liupeng0518
|
|
||||||
- mzaian
|
|
||||||
- oomichi
|
|
||||||
- yankay
|
|
||||||
- ant31
|
|
||||||
- vannten
|
|
||||||
kubespray-reviewers:
|
|
||||||
- cyclinder
|
|
||||||
- erikjiang
|
|
||||||
- mrfreezeex
|
|
||||||
- mzaian
|
|
||||||
- tico88612
|
|
||||||
- vannten
|
|
||||||
- yankay
|
|
||||||
kubespray-emeritus_approvers:
|
|
||||||
- atoms
|
|
||||||
- chadswen
|
|
||||||
- luckysb
|
|
||||||
- mattymo
|
- mattymo
|
||||||
|
- chadswen
|
||||||
|
- mirwan
|
||||||
- miouge1
|
- miouge1
|
||||||
|
- luckysb
|
||||||
|
- floryut
|
||||||
|
- oomichi
|
||||||
|
- cristicalin
|
||||||
|
- liupeng0518
|
||||||
|
- yankay
|
||||||
|
- mzaian
|
||||||
|
kubespray-reviewers:
|
||||||
|
- holmsten
|
||||||
|
- bozzo
|
||||||
|
- eppo
|
||||||
|
- oomichi
|
||||||
|
- jayonlau
|
||||||
|
- cristicalin
|
||||||
|
- liupeng0518
|
||||||
|
- yankay
|
||||||
|
- cyclinder
|
||||||
|
- mzaian
|
||||||
|
- mrfreezeex
|
||||||
|
- erikjiang
|
||||||
|
kubespray-emeritus_approvers:
|
||||||
- riverzhang
|
- riverzhang
|
||||||
|
- atoms
|
||||||
|
- ant31
|
||||||
- woopstar
|
- woopstar
|
||||||
|
|||||||
259
README.md
259
README.md
@@ -5,7 +5,7 @@
|
|||||||
If you have questions, check the documentation at [kubespray.io](https://kubespray.io) and join us on the [kubernetes slack](https://kubernetes.slack.com), channel **\#kubespray**.
|
If you have questions, check the documentation at [kubespray.io](https://kubespray.io) and join us on the [kubernetes slack](https://kubernetes.slack.com), channel **\#kubespray**.
|
||||||
You can get your invite [here](http://slack.k8s.io/)
|
You can get your invite [here](http://slack.k8s.io/)
|
||||||
|
|
||||||
- Can be deployed on **[AWS](docs/cloud_providers/aws.md), GCE, [Azure](docs/cloud_providers/azure.md), [OpenStack](docs/cloud_controllers/openstack.md), [vSphere](docs/cloud_controllers/vsphere.md), [Equinix Metal](docs/cloud_providers/equinix-metal.md) (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal**
|
- Can be deployed on **[AWS](docs/aws.md), GCE, [Azure](docs/azure.md), [OpenStack](docs/openstack.md), [vSphere](docs/vsphere.md), [Equinix Metal](docs/equinix-metal.md) (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal**
|
||||||
- **Highly available** cluster
|
- **Highly available** cluster
|
||||||
- **Composable** (Choice of the network plugin for instance)
|
- **Composable** (Choice of the network plugin for instance)
|
||||||
- Supports most popular **Linux distributions**
|
- Supports most popular **Linux distributions**
|
||||||
@@ -15,27 +15,78 @@ You can get your invite [here](http://slack.k8s.io/)
|
|||||||
|
|
||||||
Below are several ways to use Kubespray to deploy a Kubernetes cluster.
|
Below are several ways to use Kubespray to deploy a Kubernetes cluster.
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
Ensure you have installed Docker then
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
docker run --rm -it --mount type=bind,source="$(pwd)"/inventory/sample,dst=/inventory \
|
|
||||||
--mount type=bind,source="${HOME}"/.ssh/id_rsa,dst=/root/.ssh/id_rsa \
|
|
||||||
quay.io/kubespray/kubespray:v2.27.0 bash
|
|
||||||
# Inside the container you may now run the kubespray playbooks:
|
|
||||||
ansible-playbook -i /inventory/inventory.ini --private-key /root/.ssh/id_rsa cluster.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ansible
|
### Ansible
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
See [Getting started](/docs/getting_started/getting-started.md)
|
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
||||||
|
then run the following steps:
|
||||||
|
|
||||||
|
```ShellSession
|
||||||
|
# Copy ``inventory/sample`` as ``inventory/mycluster``
|
||||||
|
cp -rfp inventory/sample inventory/mycluster
|
||||||
|
|
||||||
|
# Update Ansible inventory file with inventory builder
|
||||||
|
declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)
|
||||||
|
CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
|
||||||
|
|
||||||
|
# Review and change parameters under ``inventory/mycluster/group_vars``
|
||||||
|
cat inventory/mycluster/group_vars/all/all.yml
|
||||||
|
cat inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
|
||||||
|
|
||||||
|
# Clean up old Kubernetes cluster with Ansible Playbook - run the playbook as root
|
||||||
|
# The option `--become` is required, as for example cleaning up SSL keys in /etc/,
|
||||||
|
# uninstalling old packages and interacting with various systemd daemons.
|
||||||
|
# Without --become the playbook will fail to run!
|
||||||
|
# And be mind it will remove the current kubernetes cluster (if it's running)!
|
||||||
|
ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root reset.yml
|
||||||
|
|
||||||
|
# Deploy Kubespray with Ansible Playbook - run the playbook as root
|
||||||
|
# The option `--become` is required, as for example writing SSL keys in /etc/,
|
||||||
|
# installing packages and interacting with various systemd daemons.
|
||||||
|
# Without --become the playbook will fail to run!
|
||||||
|
ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: When Ansible is already installed via system packages on the control node,
|
||||||
|
Python packages installed via `sudo pip install -r requirements.txt` will go to
|
||||||
|
a different directory tree (e.g. `/usr/local/lib/python2.7/dist-packages` on
|
||||||
|
Ubuntu) from Ansible's (e.g. `/usr/lib/python2.7/dist-packages/ansible` still on
|
||||||
|
Ubuntu). As a consequence, the `ansible-playbook` command will fail with:
|
||||||
|
|
||||||
|
```raw
|
||||||
|
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
|
||||||
|
```
|
||||||
|
|
||||||
|
This likely indicates that a task depends on a module present in ``requirements.txt``.
|
||||||
|
|
||||||
|
One way of addressing this is to uninstall the system Ansible package then
|
||||||
|
reinstall Ansible via ``pip``, but this not always possible and one must
|
||||||
|
take care regarding package versions.
|
||||||
|
A workaround consists of setting the `ANSIBLE_LIBRARY`
|
||||||
|
and `ANSIBLE_MODULE_UTILS` environment variables respectively to
|
||||||
|
the `ansible/modules` and `ansible/module_utils` subdirectories of the ``pip``
|
||||||
|
installation location, which is the ``Location`` shown by running
|
||||||
|
`pip show [package]` before executing `ansible-playbook`.
|
||||||
|
|
||||||
|
A simple way to ensure you get all the correct version of Ansible is to use
|
||||||
|
the [pre-built docker image from Quay](https://quay.io/repository/kubespray/kubespray?tab=tags).
|
||||||
|
You will then need to use [bind mounts](https://docs.docker.com/storage/bind-mounts/)
|
||||||
|
to access the inventory and SSH key in the container, like this:
|
||||||
|
|
||||||
|
```ShellSession
|
||||||
|
git checkout v2.22.1
|
||||||
|
docker pull quay.io/kubespray/kubespray:v2.22.1
|
||||||
|
docker run --rm -it --mount type=bind,source="$(pwd)"/inventory/sample,dst=/inventory \
|
||||||
|
--mount type=bind,source="${HOME}"/.ssh/id_rsa,dst=/root/.ssh/id_rsa \
|
||||||
|
quay.io/kubespray/kubespray:v2.22.1 bash
|
||||||
|
# Inside the container you may now run the kubespray playbooks:
|
||||||
|
ansible-playbook -i /inventory/inventory.ini --private-key /root/.ssh/id_rsa cluster.yml
|
||||||
|
```
|
||||||
|
|
||||||
#### Collection
|
#### Collection
|
||||||
|
|
||||||
See [here](docs/ansible/ansible_collection.md) if you wish to use this repository as an Ansible collection
|
See [here](docs/ansible_collection.md) if you wish to use this repository as an Ansible collection
|
||||||
|
|
||||||
### Vagrant
|
### Vagrant
|
||||||
|
|
||||||
@@ -48,7 +99,7 @@ python -V && pip -V
|
|||||||
|
|
||||||
If this returns the version of the software, you're good to go. If not, download and install Python from here <https://www.python.org/downloads/source/>
|
If this returns the version of the software, you're good to go. If not, download and install Python from here <https://www.python.org/downloads/source/>
|
||||||
|
|
||||||
Install Ansible according to [Ansible installation guide](/docs/ansible/ansible.md#installing-ansible)
|
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
||||||
then run the following step:
|
then run the following step:
|
||||||
|
|
||||||
```ShellSession
|
```ShellSession
|
||||||
@@ -58,104 +109,102 @@ vagrant up
|
|||||||
## Documents
|
## Documents
|
||||||
|
|
||||||
- [Requirements](#requirements)
|
- [Requirements](#requirements)
|
||||||
- [Kubespray vs ...](docs/getting_started/comparisons.md)
|
- [Kubespray vs ...](docs/comparisons.md)
|
||||||
- [Getting started](docs/getting_started/getting-started.md)
|
- [Getting started](docs/getting-started.md)
|
||||||
- [Setting up your first cluster](docs/getting_started/setting-up-your-first-cluster.md)
|
- [Setting up your first cluster](docs/setting-up-your-first-cluster.md)
|
||||||
- [Ansible inventory and tags](docs/ansible/ansible.md)
|
- [Ansible inventory and tags](docs/ansible.md)
|
||||||
- [Integration with existing ansible repo](docs/operations/integration.md)
|
- [Integration with existing ansible repo](docs/integration.md)
|
||||||
- [Deployment data variables](docs/ansible/vars.md)
|
- [Deployment data variables](docs/vars.md)
|
||||||
- [DNS stack](docs/advanced/dns-stack.md)
|
- [DNS stack](docs/dns-stack.md)
|
||||||
- [HA mode](docs/operations/ha-mode.md)
|
- [HA mode](docs/ha-mode.md)
|
||||||
- [Network plugins](#network-plugins)
|
- [Network plugins](#network-plugins)
|
||||||
- [Vagrant install](docs/developers/vagrant.md)
|
- [Vagrant install](docs/vagrant.md)
|
||||||
- [Flatcar Container Linux bootstrap](docs/operating_systems/flatcar.md)
|
- [Flatcar Container Linux bootstrap](docs/flatcar.md)
|
||||||
- [Fedora CoreOS bootstrap](docs/operating_systems/fcos.md)
|
- [Fedora CoreOS bootstrap](docs/fcos.md)
|
||||||
- [openSUSE setup](docs/operating_systems/opensuse.md)
|
- [Debian Jessie setup](docs/debian.md)
|
||||||
- [Downloaded artifacts](docs/advanced/downloads.md)
|
- [openSUSE setup](docs/opensuse.md)
|
||||||
- [Equinix Metal](docs/cloud_providers/equinix-metal.md)
|
- [Downloaded artifacts](docs/downloads.md)
|
||||||
- [OpenStack](docs/cloud_controllers/openstack.md)
|
- [Cloud providers](docs/cloud.md)
|
||||||
- [vSphere](docs/cloud_controllers/vsphere.md)
|
- [OpenStack](docs/openstack.md)
|
||||||
- [Large deployments](docs/operations/large-deployments.md)
|
- [AWS](docs/aws.md)
|
||||||
- [Adding/replacing a node](docs/operations/nodes.md)
|
- [Azure](docs/azure.md)
|
||||||
- [Upgrades basics](docs/operations/upgrades.md)
|
- [vSphere](docs/vsphere.md)
|
||||||
- [Air-Gap installation](docs/operations/offline-environment.md)
|
- [Equinix Metal](docs/equinix-metal.md)
|
||||||
- [NTP](docs/advanced/ntp.md)
|
- [Large deployments](docs/large-deployments.md)
|
||||||
- [Hardening](docs/operations/hardening.md)
|
- [Adding/replacing a node](docs/nodes.md)
|
||||||
- [Mirror](docs/operations/mirror.md)
|
- [Upgrades basics](docs/upgrades.md)
|
||||||
- [Roadmap](docs/roadmap/roadmap.md)
|
- [Air-Gap installation](docs/offline-environment.md)
|
||||||
|
- [NTP](docs/ntp.md)
|
||||||
|
- [Hardening](docs/hardening.md)
|
||||||
|
- [Mirror](docs/mirror.md)
|
||||||
|
- [Roadmap](docs/roadmap.md)
|
||||||
|
|
||||||
## Supported Linux Distributions
|
## Supported Linux Distributions
|
||||||
|
|
||||||
- **Flatcar Container Linux by Kinvolk**
|
- **Flatcar Container Linux by Kinvolk**
|
||||||
- **Debian** Bookworm, Bullseye
|
- **Debian** Bookworm, Bullseye, Buster
|
||||||
- **Ubuntu** 20.04, 22.04, 24.04
|
- **Ubuntu** 20.04, 22.04
|
||||||
- **CentOS/RHEL** [8, 9](docs/operating_systems/rhel.md#rhel-8)
|
- **CentOS/RHEL** 7, [8, 9](docs/centos.md#centos-8)
|
||||||
- **Fedora** 39, 40
|
- **Fedora** 37, 38
|
||||||
- **Fedora CoreOS** (see [fcos Note](docs/operating_systems/fcos.md))
|
- **Fedora CoreOS** (see [fcos Note](docs/fcos.md))
|
||||||
- **openSUSE** Leap 15.x/Tumbleweed
|
- **openSUSE** Leap 15.x/Tumbleweed
|
||||||
- **Oracle Linux** [8, 9](docs/operating_systems/rhel.md#rhel-8)
|
- **Oracle Linux** 7, [8, 9](docs/centos.md#centos-8)
|
||||||
- **Alma Linux** [8, 9](docs/operating_systems/rhel.md#rhel-8)
|
- **Alma Linux** [8, 9](docs/centos.md#centos-8)
|
||||||
- **Rocky Linux** [8, 9](docs/operating_systems/rhel.md#rhel-8)
|
- **Rocky Linux** [8, 9](docs/centos.md#centos-8)
|
||||||
- **Kylin Linux Advanced Server V10** (experimental: see [kylin linux notes](docs/operating_systems/kylinlinux.md))
|
- **Kylin Linux Advanced Server V10** (experimental: see [kylin linux notes](docs/kylinlinux.md))
|
||||||
- **Amazon Linux 2** (experimental: see [amazon linux notes](docs/operating_systems/amazonlinux.md))
|
- **Amazon Linux 2** (experimental: see [amazon linux notes](docs/amazonlinux.md))
|
||||||
- **UOS Linux** (experimental: see [uos linux notes](docs/operating_systems/uoslinux.md))
|
- **UOS Linux** (experimental: see [uos linux notes](docs/uoslinux.md))
|
||||||
- **openEuler** (experimental: see [openEuler notes](docs/operating_systems/openeuler.md))
|
- **openEuler** (experimental: see [openEuler notes](docs/openeuler.md))
|
||||||
|
|
||||||
Note:
|
Note: Upstart/SysV init based OS types are not supported.
|
||||||
|
|
||||||
- Upstart/SysV init based OS types are not supported.
|
|
||||||
- [Kernel requirements](docs/operations/kernel-requirements.md) (please read if the OS kernel version is < 4.19).
|
|
||||||
|
|
||||||
## Supported Components
|
## Supported Components
|
||||||
|
|
||||||
<!-- BEGIN ANSIBLE MANAGED BLOCK -->
|
|
||||||
|
|
||||||
- Core
|
- Core
|
||||||
- [kubernetes](https://github.com/kubernetes/kubernetes) 1.32.3
|
- [kubernetes](https://github.com/kubernetes/kubernetes) v1.27.7
|
||||||
- [etcd](https://github.com/etcd-io/etcd) 3.5.16
|
- [etcd](https://github.com/etcd-io/etcd) v3.5.9
|
||||||
- [docker](https://www.docker.com/) 28.0
|
- [docker](https://www.docker.com/) v20.10 (see note)
|
||||||
- [containerd](https://containerd.io/) 2.0.3
|
- [containerd](https://containerd.io/) v1.7.5
|
||||||
- [cri-o](http://cri-o.io/) 1.32.0 (experimental: see [CRI-O Note](docs/CRI/cri-o.md). Only on fedora, ubuntu and centos based OS)
|
- [cri-o](http://cri-o.io/) v1.27 (experimental: see [CRI-O Note](docs/cri-o.md). Only on fedora, ubuntu and centos based OS)
|
||||||
- Network Plugin
|
- Network Plugin
|
||||||
- [cni-plugins](https://github.com/containernetworking/plugins) 1.4.1
|
- [cni-plugins](https://github.com/containernetworking/plugins) v1.2.0
|
||||||
- [calico](https://github.com/projectcalico/calico) 3.29.2
|
- [calico](https://github.com/projectcalico/calico) v3.25.2
|
||||||
- [cilium](https://github.com/cilium/cilium) 1.15.9
|
- [cilium](https://github.com/cilium/cilium) v1.13.4
|
||||||
- [flannel](https://github.com/flannel-io/flannel) 0.22.0
|
- [flannel](https://github.com/flannel-io/flannel) v0.22.0
|
||||||
- [kube-ovn](https://github.com/alauda/kube-ovn) 1.12.21
|
- [kube-ovn](https://github.com/alauda/kube-ovn) v1.11.5
|
||||||
- [kube-router](https://github.com/cloudnativelabs/kube-router) 2.0.0
|
- [kube-router](https://github.com/cloudnativelabs/kube-router) v1.5.1
|
||||||
- [multus](https://github.com/k8snetworkplumbingwg/multus-cni) 4.1.0
|
- [multus](https://github.com/k8snetworkplumbingwg/multus-cni) v3.8
|
||||||
- [weave](https://github.com/rajch/weave) 2.8.7
|
- [weave](https://github.com/weaveworks/weave) v2.8.1
|
||||||
- [kube-vip](https://github.com/kube-vip/kube-vip) 0.8.0
|
- [kube-vip](https://github.com/kube-vip/kube-vip) v0.5.12
|
||||||
- Application
|
- Application
|
||||||
- [cert-manager](https://github.com/jetstack/cert-manager) 1.15.3
|
- [cert-manager](https://github.com/jetstack/cert-manager) v1.11.1
|
||||||
- [coredns](https://github.com/coredns/coredns) 1.11.3
|
- [coredns](https://github.com/coredns/coredns) v1.10.1
|
||||||
- [ingress-nginx](https://github.com/kubernetes/ingress-nginx) 1.12.1
|
- [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v1.8.1
|
||||||
- [argocd](https://argoproj.github.io/) 2.14.5
|
- [krew](https://github.com/kubernetes-sigs/krew) v0.4.4
|
||||||
- [helm](https://helm.sh/) 3.16.4
|
- [argocd](https://argoproj.github.io/) v2.8.0
|
||||||
- [metallb](https://metallb.universe.tf/) 0.13.9
|
- [helm](https://helm.sh/) v3.12.3
|
||||||
- [registry](https://github.com/distribution/distribution) 2.8.1
|
- [metallb](https://metallb.universe.tf/) v0.13.9
|
||||||
|
- [registry](https://github.com/distribution/distribution) v2.8.1
|
||||||
- Storage Plugin
|
- Storage Plugin
|
||||||
- [cephfs-provisioner](https://github.com/kubernetes-incubator/external-storage) 2.1.0-k8s1.11
|
- [cephfs-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.0-k8s1.11
|
||||||
- [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) 2.1.1-k8s1.11
|
- [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.1-k8s1.11
|
||||||
- [aws-ebs-csi-plugin](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) 0.5.0
|
- [aws-ebs-csi-plugin](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) v0.5.0
|
||||||
- [azure-csi-plugin](https://github.com/kubernetes-sigs/azuredisk-csi-driver) 1.10.0
|
- [azure-csi-plugin](https://github.com/kubernetes-sigs/azuredisk-csi-driver) v1.10.0
|
||||||
- [cinder-csi-plugin](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/cinder-csi-plugin/using-cinder-csi-plugin.md) 1.30.0
|
- [cinder-csi-plugin](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/cinder-csi-plugin/using-cinder-csi-plugin.md) v1.22.0
|
||||||
- [gcp-pd-csi-plugin](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver) 1.9.2
|
- [gcp-pd-csi-plugin](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver) v1.9.2
|
||||||
- [local-path-provisioner](https://github.com/rancher/local-path-provisioner) 0.0.24
|
- [local-path-provisioner](https://github.com/rancher/local-path-provisioner) v0.0.24
|
||||||
- [local-volume-provisioner](https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner) 2.5.0
|
- [local-volume-provisioner](https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner) v2.5.0
|
||||||
- [node-feature-discovery](https://github.com/kubernetes-sigs/node-feature-discovery) 0.16.4
|
|
||||||
|
|
||||||
<!-- END ANSIBLE MANAGED BLOCK -->
|
|
||||||
|
|
||||||
## Container Runtime Notes
|
## Container Runtime Notes
|
||||||
|
|
||||||
|
- Supported Docker versions are 18.09, 19.03, 20.10, 23.0 and 24.0. The *recommended* Docker version is 20.10 (except on Debian bookworm which without supporting for 20.10 and below any more). `Kubelet` might break on docker's non-standard version numbering (it no longer uses semantic versioning). To ensure auto-updates don't break your cluster look into e.g. the YUM ``versionlock`` plugin or ``apt pin``).
|
||||||
- The cri-o version should be aligned with the respective kubernetes version (i.e. kube_version=1.20.x, crio_version=1.20)
|
- The cri-o version should be aligned with the respective kubernetes version (i.e. kube_version=1.20.x, crio_version=1.20)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **Minimum required version of Kubernetes is v1.30**
|
- **Minimum required version of Kubernetes is v1.25**
|
||||||
- **Ansible v2.14+, Jinja 2.11+ and python-netaddr is installed on the machine that will run Ansible commands**
|
- **Ansible v2.14+, Jinja 2.11+ and python-netaddr is installed on the machine that will run Ansible commands**
|
||||||
- The target servers must have **access to the Internet** in order to pull docker images. Otherwise, additional configuration is required (See [Offline Environment](docs/operations/offline-environment.md))
|
- The target servers must have **access to the Internet** in order to pull docker images. Otherwise, additional configuration is required (See [Offline Environment](docs/offline-environment.md))
|
||||||
- The target servers are configured to allow **IPv4 forwarding**.
|
- The target servers are configured to allow **IPv4 forwarding**.
|
||||||
- If using IPv6 for pods and services, the target servers are configured to allow **IPv6 forwarding**.
|
- If using IPv6 for pods and services, the target servers are configured to allow **IPv6 forwarding**.
|
||||||
- The **firewalls are not managed**, you'll need to implement your own rules the way you used to.
|
- The **firewalls are not managed**, you'll need to implement your own rules the way you used to.
|
||||||
@@ -167,16 +216,16 @@ Note:
|
|||||||
Hardware:
|
Hardware:
|
||||||
These limits are safeguarded by Kubespray. Actual requirements for your workload can differ. For a sizing guide go to the [Building Large Clusters](https://kubernetes.io/docs/setup/cluster-large/#size-of-master-and-master-components) guide.
|
These limits are safeguarded by Kubespray. Actual requirements for your workload can differ. For a sizing guide go to the [Building Large Clusters](https://kubernetes.io/docs/setup/cluster-large/#size-of-master-and-master-components) guide.
|
||||||
|
|
||||||
- Control Plane
|
- Master
|
||||||
- Memory: 2 GB
|
- Memory: 1500 MB
|
||||||
- Worker Node
|
- Node
|
||||||
- Memory: 1 GB
|
- Memory: 1024 MB
|
||||||
|
|
||||||
## Network Plugins
|
## Network Plugins
|
||||||
|
|
||||||
You can choose among ten network plugins. (default: `calico`, except Vagrant uses `flannel`)
|
You can choose among ten network plugins. (default: `calico`, except Vagrant uses `flannel`)
|
||||||
|
|
||||||
- [flannel](docs/CNI/flannel.md): gre/vxlan (layer 2) networking.
|
- [flannel](docs/flannel.md): gre/vxlan (layer 2) networking.
|
||||||
|
|
||||||
- [Calico](https://docs.tigera.io/calico/latest/about/) is a networking and network policy provider. Calico supports a flexible set of networking options
|
- [Calico](https://docs.tigera.io/calico/latest/about/) is a networking and network policy provider. Calico supports a flexible set of networking options
|
||||||
designed to give you the most efficient networking across a range of situations, including non-overlay
|
designed to give you the most efficient networking across a range of situations, including non-overlay
|
||||||
@@ -185,32 +234,32 @@ You can choose among ten network plugins. (default: `calico`, except Vagrant use
|
|||||||
|
|
||||||
- [cilium](http://docs.cilium.io/en/latest/): layer 3/4 networking (as well as layer 7 to protect and secure application protocols), supports dynamic insertion of BPF bytecode into the Linux kernel to implement security services, networking and visibility logic.
|
- [cilium](http://docs.cilium.io/en/latest/): layer 3/4 networking (as well as layer 7 to protect and secure application protocols), supports dynamic insertion of BPF bytecode into the Linux kernel to implement security services, networking and visibility logic.
|
||||||
|
|
||||||
- [weave](docs/CNI/weave.md): Weave is a lightweight container overlay network that doesn't require an external K/V database cluster.
|
- [weave](docs/weave.md): Weave is a lightweight container overlay network that doesn't require an external K/V database cluster.
|
||||||
(Please refer to `weave` [troubleshooting documentation](https://www.weave.works/docs/net/latest/troubleshooting/)).
|
(Please refer to `weave` [troubleshooting documentation](https://www.weave.works/docs/net/latest/troubleshooting/)).
|
||||||
|
|
||||||
- [kube-ovn](docs/CNI/kube-ovn.md): Kube-OVN integrates the OVN-based Network Virtualization with Kubernetes. It offers an advanced Container Network Fabric for Enterprises.
|
- [kube-ovn](docs/kube-ovn.md): Kube-OVN integrates the OVN-based Network Virtualization with Kubernetes. It offers an advanced Container Network Fabric for Enterprises.
|
||||||
|
|
||||||
- [kube-router](docs/CNI/kube-router.md): Kube-router is a L3 CNI for Kubernetes networking aiming to provide operational
|
- [kube-router](docs/kube-router.md): Kube-router is a L3 CNI for Kubernetes networking aiming to provide operational
|
||||||
simplicity and high performance: it uses IPVS to provide Kube Services Proxy (if setup to replace kube-proxy),
|
simplicity and high performance: it uses IPVS to provide Kube Services Proxy (if setup to replace kube-proxy),
|
||||||
iptables for network policies, and BGP for ods L3 networking (with optionally BGP peering with out-of-cluster BGP peers).
|
iptables for network policies, and BGP for ods L3 networking (with optionally BGP peering with out-of-cluster BGP peers).
|
||||||
It can also optionally advertise routes to Kubernetes cluster Pods CIDRs, ClusterIPs, ExternalIPs and LoadBalancerIPs.
|
It can also optionally advertise routes to Kubernetes cluster Pods CIDRs, ClusterIPs, ExternalIPs and LoadBalancerIPs.
|
||||||
|
|
||||||
- [macvlan](docs/CNI/macvlan.md): Macvlan is a Linux network driver. Pods have their own unique Mac and Ip address, connected directly the physical (layer 2) network.
|
- [macvlan](docs/macvlan.md): Macvlan is a Linux network driver. Pods have their own unique Mac and Ip address, connected directly the physical (layer 2) network.
|
||||||
|
|
||||||
- [multus](docs/CNI/multus.md): Multus is a meta CNI plugin that provides multiple network interface support to pods. For each interface Multus delegates CNI calls to secondary CNI plugins such as Calico, macvlan, etc.
|
- [multus](docs/multus.md): Multus is a meta CNI plugin that provides multiple network interface support to pods. For each interface Multus delegates CNI calls to secondary CNI plugins such as Calico, macvlan, etc.
|
||||||
|
|
||||||
- [custom_cni](roles/network-plugin/custom_cni/) : You can specify some manifests that will be applied to the clusters to bring you own CNI and use non-supported ones by Kubespray.
|
- [custom_cni](roles/network-plugin/custom_cni/) : You can specify some manifests that will be applied to the clusters to bring you own CNI and use non-supported ones by Kubespray.
|
||||||
See `tests/files/custom_cni/README.md` and `tests/files/custom_cni/values.yaml`for an example with a CNI provided by a Helm Chart.
|
See `tests/files/custom_cni/README.md` and `tests/files/custom_cni/values.yaml`for an example with a CNI provided by a Helm Chart.
|
||||||
|
|
||||||
The network plugin to use is defined by the variable `kube_network_plugin`. There is also an
|
The network plugin to use is defined by the variable `kube_network_plugin`. There is also an
|
||||||
option to leverage built-in cloud provider networking instead.
|
option to leverage built-in cloud provider networking instead.
|
||||||
See also [Network checker](docs/advanced/netcheck.md).
|
See also [Network checker](docs/netcheck.md).
|
||||||
|
|
||||||
## Ingress Plugins
|
## Ingress Plugins
|
||||||
|
|
||||||
- [nginx](https://kubernetes.github.io/ingress-nginx): the NGINX Ingress Controller.
|
- [nginx](https://kubernetes.github.io/ingress-nginx): the NGINX Ingress Controller.
|
||||||
|
|
||||||
- [metallb](docs/ingress/metallb.md): the MetalLB bare-metal service LoadBalancer provider.
|
- [metallb](docs/metallb.md): the MetalLB bare-metal service LoadBalancer provider.
|
||||||
|
|
||||||
## Community docs and resources
|
## Community docs and resources
|
||||||
|
|
||||||
@@ -231,4 +280,4 @@ See also [Network checker](docs/advanced/netcheck.md).
|
|||||||
|
|
||||||
CI/end-to-end tests sponsored by: [CNCF](https://cncf.io), [Equinix Metal](https://metal.equinix.com/), [OVHcloud](https://www.ovhcloud.com/), [ELASTX](https://elastx.se/).
|
CI/end-to-end tests sponsored by: [CNCF](https://cncf.io), [Equinix Metal](https://metal.equinix.com/), [OVHcloud](https://www.ovhcloud.com/), [ELASTX](https://elastx.se/).
|
||||||
|
|
||||||
See the [test matrix](docs/developers/test_cases.md) for details.
|
See the [test matrix](docs/test_cases.md) for details.
|
||||||
|
|||||||
24
RELEASE.md
24
RELEASE.md
@@ -3,19 +3,17 @@
|
|||||||
The Kubespray Project is released on an as-needed basis. The process is as follows:
|
The Kubespray Project is released on an as-needed basis. The process is as follows:
|
||||||
|
|
||||||
1. An issue is proposing a new release with a changelog since the last release. Please see [a good sample issue](https://github.com/kubernetes-sigs/kubespray/issues/8325)
|
1. An issue is proposing a new release with a changelog since the last release. Please see [a good sample issue](https://github.com/kubernetes-sigs/kubespray/issues/8325)
|
||||||
1. At least one of the [approvers](OWNERS_ALIASES) must approve this release
|
2. At least one of the [approvers](OWNERS_ALIASES) must approve this release
|
||||||
1. (Only for major releases) The `kube_version_min_required` variable is set to `n-1`
|
3. The `kube_version_min_required` variable is set to `n-1`
|
||||||
1. (Only for major releases) Remove hashes for [EOL versions](https://github.com/kubernetes/website/blob/main/content/en/releases/patch-releases.md) of kubernetes from `*_checksums` variables.
|
4. Remove hashes for [EOL versions](https://github.com/kubernetes/website/blob/main/content/en/releases/patch-releases.md) of kubernetes from `*_checksums` variables.
|
||||||
1. Create the release note with [Kubernetes Release Notes Generator](https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md). See the following `Release note creation` section for the details.
|
5. Create the release note with [Kubernetes Release Notes Generator](https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md). See the following `Release note creation` section for the details.
|
||||||
1. An approver creates [new release in GitHub](https://github.com/kubernetes-sigs/kubespray/releases/new) using a version and tag name like `vX.Y.Z` and attaching the release notes
|
6. An approver creates [new release in GitHub](https://github.com/kubernetes-sigs/kubespray/releases/new) using a version and tag name like `vX.Y.Z` and attaching the release notes
|
||||||
1. (Only for major releases) An approver creates a release branch in the form `release-X.Y`
|
7. An approver creates a release branch in the form `release-X.Y`
|
||||||
1. (For major releases) On the `master` branch: bump the version in `galaxy.yml` to the next expected major release (X.y.0 with y = Y + 1), make a Pull Request.
|
8. The corresponding version of [quay.io/kubespray/kubespray:vX.Y.Z](https://quay.io/repository/kubespray/kubespray) and [quay.io/kubespray/vagrant:vX.Y.Z](https://quay.io/repository/kubespray/vagrant) container images are built and tagged. See the following `Container image creation` section for the details.
|
||||||
1. (For minor releases) On the `release-X.Y` branch: bump the version in `galaxy.yml` to the next expected minor release (X.Y.z with z = Z + 1), make a Pull Request.
|
9. The `KUBESPRAY_VERSION` variable is updated in `.gitlab-ci.yml`
|
||||||
1. The corresponding version of [quay.io/kubespray/kubespray:vX.Y.Z](https://quay.io/repository/kubespray/kubespray) and [quay.io/kubespray/vagrant:vX.Y.Z](https://quay.io/repository/kubespray/vagrant) container images are built and tagged. See the following `Container image creation` section for the details.
|
10. The release issue is closed
|
||||||
1. The release issue is closed
|
11. An announcement email is sent to `dev@kubernetes.io` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
|
||||||
1. An announcement email is sent to `dev@kubernetes.io` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
|
12. The topic of the #kubespray channel is updated with `vX.Y.Z is released! | ...`
|
||||||
1. The topic of the #kubespray channel is updated with `vX.Y.Z is released! | ...`
|
|
||||||
1. Create/Update Issue for upgradeing kubernetes and [k8s-conformance](https://github.com/cncf/k8s-conformance)
|
|
||||||
|
|
||||||
## Major/minor releases and milestones
|
## Major/minor releases and milestones
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
|
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
|
||||||
# INSTRUCTIONS AT https://kubernetes.io/security/
|
# INSTRUCTIONS AT https://kubernetes.io/security/
|
||||||
|
mattymo
|
||||||
floryut
|
floryut
|
||||||
ant31
|
oomichi
|
||||||
VannTen
|
cristicalin
|
||||||
yankay
|
|
||||||
|
|||||||
106
Vagrantfile
vendored
106
Vagrantfile
vendored
@@ -1,7 +1,7 @@
|
|||||||
# -*- mode: ruby -*-
|
# -*- mode: ruby -*-
|
||||||
# # vi: set ft=ruby :
|
# # vi: set ft=ruby :
|
||||||
|
|
||||||
# For help on using kubespray with vagrant, check out docs/developers/vagrant.md
|
# For help on using kubespray with vagrant, check out docs/vagrant.md
|
||||||
|
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
|
||||||
@@ -21,25 +21,21 @@ SUPPORTED_OS = {
|
|||||||
"flatcar-edge" => {box: "flatcar-edge", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["edge"]},
|
"flatcar-edge" => {box: "flatcar-edge", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["edge"]},
|
||||||
"ubuntu2004" => {box: "generic/ubuntu2004", user: "vagrant"},
|
"ubuntu2004" => {box: "generic/ubuntu2004", user: "vagrant"},
|
||||||
"ubuntu2204" => {box: "generic/ubuntu2204", user: "vagrant"},
|
"ubuntu2204" => {box: "generic/ubuntu2204", user: "vagrant"},
|
||||||
"ubuntu2404" => {box: "bento/ubuntu-24.04", user: "vagrant"},
|
"centos" => {box: "centos/7", user: "vagrant"},
|
||||||
|
"centos-bento" => {box: "bento/centos-7.6", user: "vagrant"},
|
||||||
"centos8" => {box: "centos/8", user: "vagrant"},
|
"centos8" => {box: "centos/8", user: "vagrant"},
|
||||||
"centos8-bento" => {box: "bento/centos-8", user: "vagrant"},
|
"centos8-bento" => {box: "bento/centos-8", user: "vagrant"},
|
||||||
"almalinux8" => {box: "almalinux/8", user: "vagrant"},
|
"almalinux8" => {box: "almalinux/8", user: "vagrant"},
|
||||||
"almalinux8-bento" => {box: "bento/almalinux-8", user: "vagrant"},
|
"almalinux8-bento" => {box: "bento/almalinux-8", user: "vagrant"},
|
||||||
"almalinux9" => {box: "almalinux/9", user: "vagrant"},
|
"rockylinux8" => {box: "generic/rocky8", user: "vagrant"},
|
||||||
"rockylinux8" => {box: "rockylinux/8", user: "vagrant"},
|
"fedora37" => {box: "fedora/37-cloud-base", user: "vagrant"},
|
||||||
"rockylinux9" => {box: "rockylinux/9", user: "vagrant"},
|
"fedora38" => {box: "fedora/38-cloud-base", user: "vagrant"},
|
||||||
"fedora39" => {box: "fedora/39-cloud-base", user: "vagrant"},
|
"opensuse" => {box: "opensuse/Leap-15.4.x86_64", user: "vagrant"},
|
||||||
"fedora40" => {box: "fedora/40-cloud-base", user: "vagrant"},
|
|
||||||
"fedora39-arm64" => {box: "bento/fedora-39-arm64", user: "vagrant"},
|
|
||||||
"fedora40-arm64" => {box: "bento/fedora-40", user: "vagrant"},
|
|
||||||
"opensuse" => {box: "opensuse/Leap-15.6.x86_64", user: "vagrant"},
|
|
||||||
"opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
|
"opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
|
||||||
"oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
|
"oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
|
||||||
"oraclelinux8" => {box: "generic/oracle8", user: "vagrant"},
|
"oraclelinux8" => {box: "generic/oracle8", user: "vagrant"},
|
||||||
|
"rhel7" => {box: "generic/rhel7", user: "vagrant"},
|
||||||
"rhel8" => {box: "generic/rhel8", user: "vagrant"},
|
"rhel8" => {box: "generic/rhel8", user: "vagrant"},
|
||||||
"debian11" => {box: "debian/bullseye64", user: "vagrant"},
|
|
||||||
"debian12" => {box: "debian/bookworm64", user: "vagrant"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if File.exist?(CONFIG)
|
if File.exist?(CONFIG)
|
||||||
@@ -58,27 +54,16 @@ $subnet ||= "172.18.8"
|
|||||||
$subnet_ipv6 ||= "fd3c:b398:0698:0756"
|
$subnet_ipv6 ||= "fd3c:b398:0698:0756"
|
||||||
$os ||= "ubuntu2004"
|
$os ||= "ubuntu2004"
|
||||||
$network_plugin ||= "flannel"
|
$network_plugin ||= "flannel"
|
||||||
$inventories ||= []
|
|
||||||
# Setting multi_networking to true will install Multus: https://github.com/k8snetworkplumbingwg/multus-cni
|
# Setting multi_networking to true will install Multus: https://github.com/k8snetworkplumbingwg/multus-cni
|
||||||
$multi_networking ||= "False"
|
$multi_networking ||= "False"
|
||||||
$download_run_once ||= "True"
|
$download_run_once ||= "True"
|
||||||
$download_force_cache ||= "False"
|
$download_force_cache ||= "False"
|
||||||
# Modify those to have separate groups (for instance, to test separate etcd:)
|
|
||||||
# first_control_plane = 1
|
|
||||||
# first_etcd = 4
|
|
||||||
# control_plane_instances = 3
|
|
||||||
# etcd_instances = 3
|
|
||||||
$first_node ||= 1
|
|
||||||
$first_control_plane ||= 1
|
|
||||||
$first_etcd ||= 1
|
|
||||||
|
|
||||||
# The first three nodes are etcd servers
|
# The first three nodes are etcd servers
|
||||||
$etcd_instances ||= [$num_instances, 3].min
|
$etcd_instances ||= [$num_instances, 3].min
|
||||||
# The first two nodes are kube masters
|
# The first two nodes are kube masters
|
||||||
$control_plane_instances ||= [$num_instances, 2].min
|
$kube_master_instances ||= [$num_instances, 2].min
|
||||||
# All nodes are kube nodes
|
# All nodes are kube nodes
|
||||||
$kube_node_instances ||= $num_instances - $first_node + 1
|
$kube_node_instances ||= $num_instances
|
||||||
|
|
||||||
# The following only works when using the libvirt provider
|
# The following only works when using the libvirt provider
|
||||||
$kube_node_instances_with_disks ||= false
|
$kube_node_instances_with_disks ||= false
|
||||||
$kube_node_instances_with_disks_size ||= "20G"
|
$kube_node_instances_with_disks_size ||= "20G"
|
||||||
@@ -92,10 +77,7 @@ $libvirt_nested ||= false
|
|||||||
$ansible_verbosity ||= false
|
$ansible_verbosity ||= false
|
||||||
$ansible_tags ||= ENV['VAGRANT_ANSIBLE_TAGS'] || ""
|
$ansible_tags ||= ENV['VAGRANT_ANSIBLE_TAGS'] || ""
|
||||||
|
|
||||||
$vagrant_dir ||= File.join(File.dirname(__FILE__), ".vagrant")
|
|
||||||
|
|
||||||
$playbook ||= "cluster.yml"
|
$playbook ||= "cluster.yml"
|
||||||
$extra_vars ||= {}
|
|
||||||
|
|
||||||
host_vars = {}
|
host_vars = {}
|
||||||
|
|
||||||
@@ -107,6 +89,19 @@ if ! SUPPORTED_OS.key?($os)
|
|||||||
end
|
end
|
||||||
|
|
||||||
$box = SUPPORTED_OS[$os][:box]
|
$box = SUPPORTED_OS[$os][:box]
|
||||||
|
# if $inventory is not set, try to use example
|
||||||
|
$inventory = "inventory/sample" if ! $inventory
|
||||||
|
$inventory = File.absolute_path($inventory, File.dirname(__FILE__))
|
||||||
|
|
||||||
|
# if $inventory has a hosts.ini file use it, otherwise copy over
|
||||||
|
# vars etc to where vagrant expects dynamic inventory to be
|
||||||
|
if ! File.exist?(File.join(File.dirname($inventory), "hosts.ini"))
|
||||||
|
$vagrant_ansible = File.join(File.dirname(__FILE__), ".vagrant", "provisioners", "ansible")
|
||||||
|
FileUtils.mkdir_p($vagrant_ansible) if ! File.exist?($vagrant_ansible)
|
||||||
|
$vagrant_inventory = File.join($vagrant_ansible,"inventory")
|
||||||
|
FileUtils.rm_f($vagrant_inventory)
|
||||||
|
FileUtils.ln_s($inventory, $vagrant_inventory)
|
||||||
|
end
|
||||||
|
|
||||||
if Vagrant.has_plugin?("vagrant-proxyconf")
|
if Vagrant.has_plugin?("vagrant-proxyconf")
|
||||||
$no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
|
$no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
|
||||||
@@ -187,14 +182,6 @@ Vagrant.configure("2") do |config|
|
|||||||
lv.storage :file, :device => "hd#{driverletters[d]}", :path => "disk-#{i}-#{d}-#{DISK_UUID}.disk", :size => $kube_node_instances_with_disks_size, :bus => "scsi"
|
lv.storage :file, :device => "hd#{driverletters[d]}", :path => "disk-#{i}-#{d}-#{DISK_UUID}.disk", :size => $kube_node_instances_with_disks_size, :bus => "scsi"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
node.vm.provider :virtualbox do |vb|
|
|
||||||
# always make /dev/sd{a/b/c} so that CI can ensure that
|
|
||||||
# virtualbox and libvirt will have the same devices to use for OSDs
|
|
||||||
(1..$kube_node_instances_with_disks_number).each do |d|
|
|
||||||
vb.customize ['createhd', '--filename', "disk-#{i}-#{driverletters[d]}-#{DISK_UUID}.disk", '--size', $kube_node_instances_with_disks_size] # 10GB disk
|
|
||||||
vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', d, '--device', 0, '--type', 'hdd', '--medium', "disk-#{i}-#{driverletters[d]}-#{DISK_UUID}.disk", '--nonrotational', 'on', '--mtype', 'normal']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if $expose_docker_tcp
|
if $expose_docker_tcp
|
||||||
@@ -205,7 +192,7 @@ Vagrant.configure("2") do |config|
|
|||||||
node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true
|
node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true
|
||||||
end
|
end
|
||||||
|
|
||||||
if ["rhel8"].include? $os
|
if ["rhel7","rhel8"].include? $os
|
||||||
# Vagrant synced_folder rsync options cannot be used for RHEL boxes as Rsync package cannot
|
# Vagrant synced_folder rsync options cannot be used for RHEL boxes as Rsync package cannot
|
||||||
# be installed until the host is registered with a valid Red Hat support subscription
|
# be installed until the host is registered with a valid Red Hat support subscription
|
||||||
node.vm.synced_folder ".", "/vagrant", disabled: false
|
node.vm.synced_folder ".", "/vagrant", disabled: false
|
||||||
@@ -220,20 +207,14 @@ Vagrant.configure("2") do |config|
|
|||||||
end
|
end
|
||||||
|
|
||||||
ip = "#{$subnet}.#{i+100}"
|
ip = "#{$subnet}.#{i+100}"
|
||||||
ip6 = "#{$subnet_ipv6}::#{i+100}"
|
|
||||||
node.vm.network :private_network,
|
node.vm.network :private_network,
|
||||||
:ip => ip,
|
:ip => ip,
|
||||||
:libvirt__guest_ipv6 => 'yes',
|
:libvirt__guest_ipv6 => 'yes',
|
||||||
:libvirt__ipv6_address => ip6,
|
:libvirt__ipv6_address => "#{$subnet_ipv6}::#{i+100}",
|
||||||
:libvirt__ipv6_prefix => "64",
|
:libvirt__ipv6_prefix => "64",
|
||||||
:libvirt__forward_mode => "none",
|
:libvirt__forward_mode => "none",
|
||||||
:libvirt__dhcp_enabled => false
|
:libvirt__dhcp_enabled => false
|
||||||
|
|
||||||
# libvirt__ipv6_address does not work as intended, the address is obtained with the desired prefix, but auto-generated(like fd3c:b398:698:756:5054:ff:fe48:c61e/64)
|
|
||||||
# add default route for detect ansible_default_ipv6
|
|
||||||
# TODO: fix libvirt__ipv6 or use $subnet in shell
|
|
||||||
config.vm.provision "shell", inline: "ip -6 r a fd3c:b398:698:756::/64 dev eth1;ip -6 r add default via fd3c:b398:0698:0756::1 dev eth1 || true"
|
|
||||||
|
|
||||||
# Disable swap for each vm
|
# Disable swap for each vm
|
||||||
node.vm.provision "shell", inline: "swapoff -a"
|
node.vm.provision "shell", inline: "swapoff -a"
|
||||||
|
|
||||||
@@ -242,25 +223,17 @@ Vagrant.configure("2") do |config|
|
|||||||
node.vm.provision "shell", inline: "rm -f /etc/modprobe.d/local.conf"
|
node.vm.provision "shell", inline: "rm -f /etc/modprobe.d/local.conf"
|
||||||
node.vm.provision "shell", inline: "sed -i '/net.ipv6.conf.all.disable_ipv6/d' /etc/sysctl.d/99-sysctl.conf /etc/sysctl.conf"
|
node.vm.provision "shell", inline: "sed -i '/net.ipv6.conf.all.disable_ipv6/d' /etc/sysctl.d/99-sysctl.conf /etc/sysctl.conf"
|
||||||
end
|
end
|
||||||
# Hack for fedora39/40 to get the IP address of the second interface
|
# Hack for fedora37/38 to get the IP address of the second interface
|
||||||
if ["fedora39", "fedora40", "fedora39-arm64", "fedora40-arm64"].include? $os
|
if ["fedora37", "fedora38"].include? $os
|
||||||
config.vm.provision "shell", inline: <<-SHELL
|
config.vm.provision "shell", inline: <<-SHELL
|
||||||
nmcli conn modify 'Wired connection 2' ipv4.addresses $(cat /etc/sysconfig/network-scripts/ifcfg-eth1 | grep IPADDR | cut -d "=" -f2)/24
|
nmcli conn modify 'Wired connection 2' ipv4.addresses $(cat /etc/sysconfig/network-scripts/ifcfg-eth1 | grep IPADDR | cut -d "=" -f2)
|
||||||
nmcli conn modify 'Wired connection 2' ipv4.method manual
|
nmcli conn modify 'Wired connection 2' ipv4.method manual
|
||||||
service NetworkManager restart
|
service NetworkManager restart
|
||||||
SHELL
|
SHELL
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Rockylinux boxes needs UEFI
|
|
||||||
if ["rockylinux8", "rockylinux9"].include? $os
|
|
||||||
config.vm.provider "libvirt" do |domain|
|
|
||||||
domain.loader = "/usr/share/OVMF/x64/OVMF_CODE.fd"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Disable firewalld on oraclelinux/redhat vms
|
# Disable firewalld on oraclelinux/redhat vms
|
||||||
if ["oraclelinux","oraclelinux8", "rhel8","rockylinux8"].include? $os
|
if ["oraclelinux","oraclelinux8","rhel7","rhel8","rockylinux8"].include? $os
|
||||||
node.vm.provision "shell", inline: "systemctl stop firewalld; systemctl disable firewalld"
|
node.vm.provision "shell", inline: "systemctl stop firewalld; systemctl disable firewalld"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -282,9 +255,7 @@ Vagrant.configure("2") do |config|
|
|||||||
"kubectl_localhost": "True",
|
"kubectl_localhost": "True",
|
||||||
"local_path_provisioner_enabled": "#{$local_path_provisioner_enabled}",
|
"local_path_provisioner_enabled": "#{$local_path_provisioner_enabled}",
|
||||||
"local_path_provisioner_claim_root": "#{$local_path_provisioner_claim_root}",
|
"local_path_provisioner_claim_root": "#{$local_path_provisioner_claim_root}",
|
||||||
"ansible_ssh_user": SUPPORTED_OS[$os][:user],
|
"ansible_ssh_user": SUPPORTED_OS[$os][:user]
|
||||||
"ansible_ssh_private_key_file": File.join(Dir.home, ".vagrant.d", "insecure_private_key"),
|
|
||||||
"unsafe_show_logs": "True"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Only execute the Ansible provisioner once, when all the machines are up and ready.
|
# Only execute the Ansible provisioner once, when all the machines are up and ready.
|
||||||
@@ -292,24 +263,23 @@ Vagrant.configure("2") do |config|
|
|||||||
if i == $num_instances
|
if i == $num_instances
|
||||||
node.vm.provision "ansible" do |ansible|
|
node.vm.provision "ansible" do |ansible|
|
||||||
ansible.playbook = $playbook
|
ansible.playbook = $playbook
|
||||||
ansible.compatibility_mode = "2.0"
|
|
||||||
ansible.verbose = $ansible_verbosity
|
ansible.verbose = $ansible_verbosity
|
||||||
|
$ansible_inventory_path = File.join( $inventory, "hosts.ini")
|
||||||
|
if File.exist?($ansible_inventory_path)
|
||||||
|
ansible.inventory_path = $ansible_inventory_path
|
||||||
|
end
|
||||||
ansible.become = true
|
ansible.become = true
|
||||||
ansible.limit = "all,localhost"
|
ansible.limit = "all,localhost"
|
||||||
ansible.host_key_checking = false
|
ansible.host_key_checking = false
|
||||||
ansible.raw_arguments = ["--forks=#{$num_instances}",
|
ansible.raw_arguments = ["--forks=#{$num_instances}", "--flush-cache", "-e ansible_become_pass=vagrant"]
|
||||||
"--flush-cache",
|
|
||||||
"-e ansible_become_pass=vagrant"] +
|
|
||||||
$inventories.map {|inv| ["-i", inv]}.flatten
|
|
||||||
ansible.host_vars = host_vars
|
ansible.host_vars = host_vars
|
||||||
ansible.extra_vars = $extra_vars
|
|
||||||
if $ansible_tags != ""
|
if $ansible_tags != ""
|
||||||
ansible.tags = [$ansible_tags]
|
ansible.tags = [$ansible_tags]
|
||||||
end
|
end
|
||||||
ansible.groups = {
|
ansible.groups = {
|
||||||
"etcd" => ["#{$instance_name_prefix}-[#{$first_etcd}:#{$etcd_instances + $first_etcd - 1}]"],
|
"etcd" => ["#{$instance_name_prefix}-[1:#{$etcd_instances}]"],
|
||||||
"kube_control_plane" => ["#{$instance_name_prefix}-[#{$first_control_plane}:#{$control_plane_instances + $first_control_plane - 1}]"],
|
"kube_control_plane" => ["#{$instance_name_prefix}-[1:#{$kube_master_instances}]"],
|
||||||
"kube_node" => ["#{$instance_name_prefix}-[#{$first_node}:#{$kube_node_instances + $first_node - 1}]"],
|
"kube_node" => ["#{$instance_name_prefix}-[1:#{$kube_node_instances}]"],
|
||||||
"k8s_cluster:children" => ["kube_control_plane", "kube_node"],
|
"k8s_cluster:children" => ["kube_control_plane", "kube_node"],
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
pipelining=True
|
pipelining=True
|
||||||
ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null
|
ansible_ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null
|
||||||
#control_path = ~/.ssh/ansible-%%r@%%h:%%p
|
#control_path = ~/.ssh/ansible-%%r@%%h:%%p
|
||||||
[defaults]
|
[defaults]
|
||||||
# https://github.com/ansible/ansible/issues/56930 (to ignore group names with - and .)
|
# https://github.com/ansible/ansible/issues/56930 (to ignore group names with - and .)
|
||||||
@@ -11,7 +11,6 @@ gathering = smart
|
|||||||
fact_caching = jsonfile
|
fact_caching = jsonfile
|
||||||
fact_caching_connection = /tmp
|
fact_caching_connection = /tmp
|
||||||
fact_caching_timeout = 86400
|
fact_caching_timeout = 86400
|
||||||
timeout = 300
|
|
||||||
stdout_callback = default
|
stdout_callback = default
|
||||||
display_skipped_hosts = no
|
display_skipped_hosts = no
|
||||||
library = ./library
|
library = ./library
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ If you need to delete all resources from a resource group, simply call:
|
|||||||
|
|
||||||
## Installing Ansible and the dependencies
|
## Installing Ansible and the dependencies
|
||||||
|
|
||||||
Install Ansible according to [Ansible installation guide](/docs/ansible/ansible.md#installing-ansible)
|
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
||||||
|
|
||||||
## Generating an inventory for kubespray
|
## Generating an inventory for kubespray
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Generate Azure inventory
|
- name: Generate Azure inventory
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: False
|
||||||
roles:
|
roles:
|
||||||
- generate-inventory
|
- generate-inventory
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Generate Azure inventory
|
- name: Generate Azure inventory
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: False
|
||||||
roles:
|
roles:
|
||||||
- generate-inventory_2
|
- generate-inventory_2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Generate Azure templates
|
- name: Generate Azure templates
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: False
|
||||||
roles:
|
roles:
|
||||||
- generate-templates
|
- generate-templates
|
||||||
|
|||||||
@@ -12,4 +12,4 @@
|
|||||||
template:
|
template:
|
||||||
src: inventory.j2
|
src: inventory.j2
|
||||||
dest: "{{ playbook_dir }}/inventory"
|
dest: "{{ playbook_dir }}/inventory"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
template:
|
template:
|
||||||
src: inventory.j2
|
src: inventory.j2
|
||||||
dest: "{{ playbook_dir }}/inventory"
|
dest: "{{ playbook_dir }}/inventory"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|
||||||
- name: Generate Load Balancer variables
|
- name: Generate Load Balancer variables
|
||||||
template:
|
template:
|
||||||
src: loadbalancer_vars.j2
|
src: loadbalancer_vars.j2
|
||||||
dest: "{{ playbook_dir }}/loadbalancer_vars.yml"
|
dest: "{{ playbook_dir }}/loadbalancer_vars.yml"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
path: "{{ base_dir }}"
|
path: "{{ base_dir }}"
|
||||||
state: directory
|
state: directory
|
||||||
recurse: true
|
recurse: true
|
||||||
mode: "0755"
|
mode: 0755
|
||||||
|
|
||||||
- name: Store json files in base_dir
|
- name: Store json files in base_dir
|
||||||
template:
|
template:
|
||||||
src: "{{ item }}"
|
src: "{{ item }}"
|
||||||
dest: "{{ base_dir }}/{{ item }}"
|
dest: "{{ base_dir }}/{{ item }}"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
with_items:
|
with_items:
|
||||||
- network.json
|
- network.json
|
||||||
- storage.json
|
- storage.json
|
||||||
|
|||||||
177
contrib/dind/README.md
Normal file
177
contrib/dind/README.md
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# Kubespray DIND experimental setup
|
||||||
|
|
||||||
|
This ansible playbook creates local docker containers
|
||||||
|
to serve as Kubernetes "nodes", which in turn will run
|
||||||
|
"normal" Kubernetes docker containers, a mode usually
|
||||||
|
called DIND (Docker-IN-Docker).
|
||||||
|
|
||||||
|
The playbook has two roles:
|
||||||
|
|
||||||
|
- dind-host: creates the "nodes" as containers in localhost, with
|
||||||
|
appropriate settings for DIND (privileged, volume mapping for dind
|
||||||
|
storage, etc).
|
||||||
|
- dind-cluster: customizes each node container to have required
|
||||||
|
system packages installed, and some utils (swapoff, lsattr)
|
||||||
|
symlinked to /bin/true to ease mimicking a real node.
|
||||||
|
|
||||||
|
This playbook has been test with Ubuntu 16.04 as host and ubuntu:16.04
|
||||||
|
as docker images (note that dind-cluster has specific customization
|
||||||
|
for these images).
|
||||||
|
|
||||||
|
The playbook also creates a `/tmp/kubespray.dind.inventory_builder.sh`
|
||||||
|
helper (wraps up running `contrib/inventory_builder/inventory.py` with
|
||||||
|
node containers IPs and prefix).
|
||||||
|
|
||||||
|
## Deploying
|
||||||
|
|
||||||
|
See below for a complete successful run:
|
||||||
|
|
||||||
|
1. Create the node containers
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# From the kubespray root dir
|
||||||
|
cd contrib/dind
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
ansible-playbook -i hosts dind-cluster.yaml
|
||||||
|
|
||||||
|
# Back to kubespray root
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: if the playbook run fails with something like below error
|
||||||
|
message, you may need to specifically set `ansible_python_interpreter`,
|
||||||
|
see `./hosts` file for an example expanded localhost entry.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
failed: [localhost] (item=kube-node1) => {"changed": false, "item": "kube-node1", "msg": "Failed to import docker or docker-py - No module named requests.exceptions. Try `pip install docker` or `pip install docker-py` (Python 2.6)"}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Customize kubespray-dind.yaml
|
||||||
|
|
||||||
|
Note that there's coupling between above created node containers
|
||||||
|
and `kubespray-dind.yaml` settings, in particular regarding selected `node_distro`
|
||||||
|
(as set in `group_vars/all/all.yaml`), and docker settings.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$EDITOR contrib/dind/kubespray-dind.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Prepare the inventory and run the playbook
|
||||||
|
|
||||||
|
```shell
|
||||||
|
INVENTORY_DIR=inventory/local-dind
|
||||||
|
mkdir -p ${INVENTORY_DIR}
|
||||||
|
rm -f ${INVENTORY_DIR}/hosts.ini
|
||||||
|
CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
||||||
|
|
||||||
|
ansible-playbook --become -e ansible_ssh_user=debian -i ${INVENTORY_DIR}/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: You could also test other distros without editing files by
|
||||||
|
passing `--extra-vars` as per below commandline,
|
||||||
|
replacing `DISTRO` by either `debian`, `ubuntu`, `centos`, `fedora`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd contrib/dind
|
||||||
|
ansible-playbook -i hosts dind-cluster.yaml --extra-vars node_distro=DISTRO
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
CONFIG_FILE=inventory/local-dind/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
||||||
|
ansible-playbook --become -e ansible_ssh_user=DISTRO -i inventory/local-dind/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml --extra-vars bootstrap_os=DISTRO
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resulting deployment
|
||||||
|
|
||||||
|
See below to get an idea on how a completed deployment looks like,
|
||||||
|
from the host where you ran kubespray playbooks.
|
||||||
|
|
||||||
|
### node_distro: debian
|
||||||
|
|
||||||
|
Running from an Ubuntu Xenial host:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ uname -a
|
||||||
|
Linux ip-xx-xx-xx-xx 4.4.0-1069-aws #79-Ubuntu SMP Mon Sep 24
|
||||||
|
15:01:41 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
|
||||||
|
|
||||||
|
$ docker ps
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
1835dd183b75 debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node5
|
||||||
|
30b0af8d2924 debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node4
|
||||||
|
3e0d1510c62f debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node3
|
||||||
|
738993566f94 debian:9.5 "sh -c 'apt-get -qy …" 44 minutes ago Up 44 minutes kube-node2
|
||||||
|
c581ef662ed2 debian:9.5 "sh -c 'apt-get -qy …" 44 minutes ago Up 44 minutes kube-node1
|
||||||
|
|
||||||
|
$ docker exec kube-node1 kubectl get node
|
||||||
|
NAME STATUS ROLES AGE VERSION
|
||||||
|
kube-node1 Ready master,node 18m v1.12.1
|
||||||
|
kube-node2 Ready master,node 17m v1.12.1
|
||||||
|
kube-node3 Ready node 17m v1.12.1
|
||||||
|
kube-node4 Ready node 17m v1.12.1
|
||||||
|
kube-node5 Ready node 17m v1.12.1
|
||||||
|
|
||||||
|
$ docker exec kube-node1 kubectl get pod --all-namespaces
|
||||||
|
NAMESPACE NAME READY STATUS RESTARTS AGE
|
||||||
|
default netchecker-agent-67489 1/1 Running 0 2m51s
|
||||||
|
default netchecker-agent-6qq6s 1/1 Running 0 2m51s
|
||||||
|
default netchecker-agent-fsw92 1/1 Running 0 2m51s
|
||||||
|
default netchecker-agent-fw6tl 1/1 Running 0 2m51s
|
||||||
|
default netchecker-agent-hostnet-8f2zb 1/1 Running 0 3m
|
||||||
|
default netchecker-agent-hostnet-gq7ml 1/1 Running 0 3m
|
||||||
|
default netchecker-agent-hostnet-jfkgv 1/1 Running 0 3m
|
||||||
|
default netchecker-agent-hostnet-kwfwx 1/1 Running 0 3m
|
||||||
|
default netchecker-agent-hostnet-r46nm 1/1 Running 0 3m
|
||||||
|
default netchecker-agent-lxdrn 1/1 Running 0 2m51s
|
||||||
|
default netchecker-server-864bd4c897-9vstl 1/1 Running 0 2m40s
|
||||||
|
default sh-68fcc6db45-qf55h 1/1 Running 1 12m
|
||||||
|
kube-system coredns-7598f59475-6vknq 1/1 Running 0 14m
|
||||||
|
kube-system coredns-7598f59475-l5q5x 1/1 Running 0 14m
|
||||||
|
kube-system kube-apiserver-kube-node1 1/1 Running 0 17m
|
||||||
|
kube-system kube-apiserver-kube-node2 1/1 Running 0 18m
|
||||||
|
kube-system kube-controller-manager-kube-node1 1/1 Running 0 18m
|
||||||
|
kube-system kube-controller-manager-kube-node2 1/1 Running 0 18m
|
||||||
|
kube-system kube-proxy-5xx9d 1/1 Running 0 17m
|
||||||
|
kube-system kube-proxy-cdqq4 1/1 Running 0 17m
|
||||||
|
kube-system kube-proxy-n64ls 1/1 Running 0 17m
|
||||||
|
kube-system kube-proxy-pswmj 1/1 Running 0 18m
|
||||||
|
kube-system kube-proxy-x89qw 1/1 Running 0 18m
|
||||||
|
kube-system kube-scheduler-kube-node1 1/1 Running 4 17m
|
||||||
|
kube-system kube-scheduler-kube-node2 1/1 Running 4 18m
|
||||||
|
kube-system kubernetes-dashboard-5db4d9f45f-548rl 1/1 Running 0 14m
|
||||||
|
kube-system nginx-proxy-kube-node3 1/1 Running 4 17m
|
||||||
|
kube-system nginx-proxy-kube-node4 1/1 Running 4 17m
|
||||||
|
kube-system nginx-proxy-kube-node5 1/1 Running 4 17m
|
||||||
|
kube-system weave-net-42bfr 2/2 Running 0 16m
|
||||||
|
kube-system weave-net-6gt8m 2/2 Running 0 16m
|
||||||
|
kube-system weave-net-88nnc 2/2 Running 0 16m
|
||||||
|
kube-system weave-net-shckr 2/2 Running 0 16m
|
||||||
|
kube-system weave-net-xr46t 2/2 Running 0 16m
|
||||||
|
|
||||||
|
$ docker exec kube-node1 curl -s http://localhost:31081/api/v1/connectivity_check
|
||||||
|
{"Message":"All 10 pods successfully reported back to the server","Absent":null,"Outdated":null}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using ./run-test-distros.sh
|
||||||
|
|
||||||
|
You can use `./run-test-distros.sh` to run a set of tests via DIND,
|
||||||
|
and excerpt from this script, to get an idea:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# The SPEC file(s) must have two arrays as e.g.
|
||||||
|
# DISTROS=(debian centos)
|
||||||
|
# EXTRAS=(
|
||||||
|
# 'kube_network_plugin=calico'
|
||||||
|
# 'kube_network_plugin=flannel'
|
||||||
|
# 'kube_network_plugin=weave'
|
||||||
|
# )
|
||||||
|
# that will be tested in a "combinatory" way (e.g. from above there'll be
|
||||||
|
# be 6 test runs), creating a sequenced <spec_filename>-nn.out with each output.
|
||||||
|
#
|
||||||
|
# Each $EXTRAS element will be whitespace split, and passed as --extra-vars
|
||||||
|
# to main kubespray ansible-playbook run.
|
||||||
|
```
|
||||||
|
|
||||||
|
See e.g. `test-some_distros-most_CNIs.env` and
|
||||||
|
`test-some_distros-kube_router_combo.env` in particular for a richer
|
||||||
|
set of CNI specific `--extra-vars` combo.
|
||||||
11
contrib/dind/dind-cluster.yaml
Normal file
11
contrib/dind/dind-cluster.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: Create nodes as docker containers
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: False
|
||||||
|
roles:
|
||||||
|
- { role: dind-host }
|
||||||
|
|
||||||
|
- name: Customize each node containers
|
||||||
|
hosts: containers
|
||||||
|
roles:
|
||||||
|
- { role: dind-cluster }
|
||||||
3
contrib/dind/group_vars/all/all.yaml
Normal file
3
contrib/dind/group_vars/all/all.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
# See distro.yaml for supported node_distro images
|
||||||
|
node_distro: debian
|
||||||
41
contrib/dind/group_vars/all/distro.yaml
Normal file
41
contrib/dind/group_vars/all/distro.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
distro_settings:
|
||||||
|
debian: &DEBIAN
|
||||||
|
image: "debian:9.5"
|
||||||
|
user: "debian"
|
||||||
|
pid1_exe: /lib/systemd/systemd
|
||||||
|
init: |
|
||||||
|
sh -c "apt-get -qy update && apt-get -qy install systemd-sysv dbus && exec /sbin/init"
|
||||||
|
raw_setup: apt-get -qy update && apt-get -qy install dbus python sudo iproute2
|
||||||
|
raw_setup_done: test -x /usr/bin/sudo
|
||||||
|
agetty_svc: getty@*
|
||||||
|
ssh_service: ssh
|
||||||
|
extra_packages: []
|
||||||
|
ubuntu:
|
||||||
|
<<: *DEBIAN
|
||||||
|
image: "ubuntu:16.04"
|
||||||
|
user: "ubuntu"
|
||||||
|
init: |
|
||||||
|
/sbin/init
|
||||||
|
centos: &CENTOS
|
||||||
|
image: "centos:7"
|
||||||
|
user: "centos"
|
||||||
|
pid1_exe: /usr/lib/systemd/systemd
|
||||||
|
init: |
|
||||||
|
/sbin/init
|
||||||
|
raw_setup: yum -qy install policycoreutils dbus python sudo iproute iptables
|
||||||
|
raw_setup_done: test -x /usr/bin/sudo
|
||||||
|
agetty_svc: getty@* serial-getty@*
|
||||||
|
ssh_service: sshd
|
||||||
|
extra_packages: []
|
||||||
|
fedora:
|
||||||
|
<<: *CENTOS
|
||||||
|
image: "fedora:latest"
|
||||||
|
user: "fedora"
|
||||||
|
raw_setup: yum -qy install policycoreutils dbus python sudo iproute iptables; mkdir -p /etc/modules-load.d
|
||||||
|
extra_packages:
|
||||||
|
- hostname
|
||||||
|
- procps
|
||||||
|
- findutils
|
||||||
|
- kmod
|
||||||
|
- iputils
|
||||||
15
contrib/dind/hosts
Normal file
15
contrib/dind/hosts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[local]
|
||||||
|
# If you created a virtualenv for ansible, you may need to specify running the
|
||||||
|
# python binary from there instead:
|
||||||
|
#localhost ansible_connection=local ansible_python_interpreter=/home/user/kubespray/.venv/bin/python
|
||||||
|
localhost ansible_connection=local
|
||||||
|
|
||||||
|
[containers]
|
||||||
|
kube-node1
|
||||||
|
kube-node2
|
||||||
|
kube-node3
|
||||||
|
kube-node4
|
||||||
|
kube-node5
|
||||||
|
|
||||||
|
[containers:vars]
|
||||||
|
ansible_connection=docker
|
||||||
22
contrib/dind/kubespray-dind.yaml
Normal file
22
contrib/dind/kubespray-dind.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
# kubespray-dind.yaml: minimal kubespray ansible playbook usable for DIND
|
||||||
|
# See contrib/dind/README.md
|
||||||
|
kube_api_anonymous_auth: true
|
||||||
|
|
||||||
|
kubelet_fail_swap_on: false
|
||||||
|
|
||||||
|
# Docker nodes need to have been created with same "node_distro: debian"
|
||||||
|
# at contrib/dind/group_vars/all/all.yaml
|
||||||
|
bootstrap_os: debian
|
||||||
|
|
||||||
|
docker_version: latest
|
||||||
|
|
||||||
|
docker_storage_options: -s overlay2 --storage-opt overlay2.override_kernel_check=true -g /dind/docker
|
||||||
|
|
||||||
|
dns_mode: coredns
|
||||||
|
|
||||||
|
deploy_netchecker: True
|
||||||
|
netcheck_agent_image_repo: quay.io/l23network/k8s-netchecker-agent
|
||||||
|
netcheck_server_image_repo: quay.io/l23network/k8s-netchecker-server
|
||||||
|
netcheck_agent_image_tag: v1.0
|
||||||
|
netcheck_server_image_tag: v1.0
|
||||||
1
contrib/dind/requirements.txt
Normal file
1
contrib/dind/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
docker
|
||||||
73
contrib/dind/roles/dind-cluster/tasks/main.yaml
Normal file
73
contrib/dind/roles/dind-cluster/tasks/main.yaml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
- name: Set_fact distro_setup
|
||||||
|
set_fact:
|
||||||
|
distro_setup: "{{ distro_settings[node_distro] }}"
|
||||||
|
|
||||||
|
- name: Set_fact other distro settings
|
||||||
|
set_fact:
|
||||||
|
distro_user: "{{ distro_setup['user'] }}"
|
||||||
|
distro_ssh_service: "{{ distro_setup['ssh_service'] }}"
|
||||||
|
distro_extra_packages: "{{ distro_setup['extra_packages'] }}"
|
||||||
|
|
||||||
|
- name: Null-ify some linux tools to ease DIND
|
||||||
|
file:
|
||||||
|
src: "/bin/true"
|
||||||
|
dest: "{{ item }}"
|
||||||
|
state: link
|
||||||
|
force: yes
|
||||||
|
with_items:
|
||||||
|
# DIND box may have swap enable, don't bother
|
||||||
|
- /sbin/swapoff
|
||||||
|
# /etc/hosts handling would fail on trying to copy file attributes on edit,
|
||||||
|
# void it by successfully returning nil output
|
||||||
|
- /usr/bin/lsattr
|
||||||
|
# disable selinux-isms, sp needed if running on non-Selinux host
|
||||||
|
- /usr/sbin/semodule
|
||||||
|
|
||||||
|
- name: Void installing dpkg docs and man pages on Debian based distros
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
# Delete locales
|
||||||
|
path-exclude=/usr/share/locale/*
|
||||||
|
# Delete man pages
|
||||||
|
path-exclude=/usr/share/man/*
|
||||||
|
# Delete docs
|
||||||
|
path-exclude=/usr/share/doc/*
|
||||||
|
path-include=/usr/share/doc/*/copyright
|
||||||
|
dest: /etc/dpkg/dpkg.cfg.d/01_nodoc
|
||||||
|
mode: 0644
|
||||||
|
when:
|
||||||
|
- ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: Install system packages to better match a full-fledge node
|
||||||
|
package:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: present
|
||||||
|
with_items: "{{ distro_extra_packages + ['rsyslog', 'openssh-server'] }}"
|
||||||
|
|
||||||
|
- name: Start needed services
|
||||||
|
service:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
with_items:
|
||||||
|
- rsyslog
|
||||||
|
- "{{ distro_ssh_service }}"
|
||||||
|
|
||||||
|
- name: Create distro user "{{ distro_user }}"
|
||||||
|
user:
|
||||||
|
name: "{{ distro_user }}"
|
||||||
|
uid: 1000
|
||||||
|
# groups: sudo
|
||||||
|
append: yes
|
||||||
|
|
||||||
|
- name: Allow password-less sudo to "{{ distro_user }}"
|
||||||
|
copy:
|
||||||
|
content: "{{ distro_user }} ALL=(ALL) NOPASSWD:ALL"
|
||||||
|
dest: "/etc/sudoers.d/{{ distro_user }}"
|
||||||
|
mode: 0640
|
||||||
|
|
||||||
|
- name: "Add my pubkey to {{ distro_user }} user authorized keys"
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ distro_user }}"
|
||||||
|
state: present
|
||||||
|
key: "{{ lookup('file', lookup('env', 'HOME') + '/.ssh/id_rsa.pub') }}"
|
||||||
87
contrib/dind/roles/dind-host/tasks/main.yaml
Normal file
87
contrib/dind/roles/dind-host/tasks/main.yaml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
- name: Set_fact distro_setup
|
||||||
|
set_fact:
|
||||||
|
distro_setup: "{{ distro_settings[node_distro] }}"
|
||||||
|
|
||||||
|
- name: Set_fact other distro settings
|
||||||
|
set_fact:
|
||||||
|
distro_image: "{{ distro_setup['image'] }}"
|
||||||
|
distro_init: "{{ distro_setup['init'] }}"
|
||||||
|
distro_pid1_exe: "{{ distro_setup['pid1_exe'] }}"
|
||||||
|
distro_raw_setup: "{{ distro_setup['raw_setup'] }}"
|
||||||
|
distro_raw_setup_done: "{{ distro_setup['raw_setup_done'] }}"
|
||||||
|
distro_agetty_svc: "{{ distro_setup['agetty_svc'] }}"
|
||||||
|
|
||||||
|
- name: Create dind node containers from "containers" inventory section
|
||||||
|
community.docker.docker_container:
|
||||||
|
image: "{{ distro_image }}"
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: started
|
||||||
|
hostname: "{{ item }}"
|
||||||
|
command: "{{ distro_init }}"
|
||||||
|
# recreate: yes
|
||||||
|
privileged: true
|
||||||
|
tmpfs:
|
||||||
|
- /sys/module/nf_conntrack/parameters
|
||||||
|
volumes:
|
||||||
|
- /boot:/boot
|
||||||
|
- /lib/modules:/lib/modules
|
||||||
|
- "{{ item }}:/dind/docker"
|
||||||
|
register: containers
|
||||||
|
with_items: "{{ groups.containers }}"
|
||||||
|
tags:
|
||||||
|
- addresses
|
||||||
|
|
||||||
|
- name: Gather list of containers IPs
|
||||||
|
set_fact:
|
||||||
|
addresses: "{{ containers.results | map(attribute='ansible_facts') | map(attribute='docker_container') | map(attribute='NetworkSettings') | map(attribute='IPAddress') | list }}"
|
||||||
|
tags:
|
||||||
|
- addresses
|
||||||
|
|
||||||
|
- name: Create inventory_builder helper already set with the list of node containers' IPs
|
||||||
|
template:
|
||||||
|
src: inventory_builder.sh.j2
|
||||||
|
dest: /tmp/kubespray.dind.inventory_builder.sh
|
||||||
|
mode: 0755
|
||||||
|
tags:
|
||||||
|
- addresses
|
||||||
|
|
||||||
|
- name: Install needed packages into node containers via raw, need to wait for possible systemd packages to finish installing
|
||||||
|
raw: |
|
||||||
|
# agetty processes churn a lot of cpu time failing on inexistent ttys, early STOP them, to rip them in below task
|
||||||
|
pkill -STOP agetty || true
|
||||||
|
{{ distro_raw_setup_done }} && echo SKIPPED && exit 0
|
||||||
|
until [ "$(readlink /proc/1/exe)" = "{{ distro_pid1_exe }}" ] ; do sleep 1; done
|
||||||
|
{{ distro_raw_setup }}
|
||||||
|
delegate_to: "{{ item._ansible_item_label | default(item.item) }}"
|
||||||
|
with_items: "{{ containers.results }}"
|
||||||
|
register: result
|
||||||
|
changed_when: result.stdout.find("SKIPPED") < 0
|
||||||
|
|
||||||
|
- name: Remove gettys from node containers
|
||||||
|
raw: |
|
||||||
|
until test -S /var/run/dbus/system_bus_socket; do sleep 1; done
|
||||||
|
systemctl disable {{ distro_agetty_svc }}
|
||||||
|
systemctl stop {{ distro_agetty_svc }}
|
||||||
|
delegate_to: "{{ item._ansible_item_label | default(item.item) }}"
|
||||||
|
with_items: "{{ containers.results }}"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# Running systemd-machine-id-setup doesn't create a unique id for each node container on Debian,
|
||||||
|
# handle manually
|
||||||
|
- name: Re-create unique machine-id (as we may just get what comes in the docker image), needed by some CNIs for mac address seeding (notably weave)
|
||||||
|
raw: |
|
||||||
|
echo {{ item | hash('sha1') }} > /etc/machine-id.new
|
||||||
|
mv -b /etc/machine-id.new /etc/machine-id
|
||||||
|
cmp /etc/machine-id /etc/machine-id~ || true
|
||||||
|
systemctl daemon-reload
|
||||||
|
delegate_to: "{{ item._ansible_item_label | default(item.item) }}"
|
||||||
|
with_items: "{{ containers.results }}"
|
||||||
|
|
||||||
|
- name: Early hack image install to adapt for DIND
|
||||||
|
raw: |
|
||||||
|
rm -fv /usr/bin/udevadm /usr/sbin/udevadm
|
||||||
|
delegate_to: "{{ item._ansible_item_label | default(item.item) }}"
|
||||||
|
with_items: "{{ containers.results }}"
|
||||||
|
register: result
|
||||||
|
changed_when: result.stdout.find("removed") >= 0
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# NOTE: if you change HOST_PREFIX, you also need to edit ./hosts [containers] section
|
||||||
|
HOST_PREFIX=kube-node python3 contrib/inventory_builder/inventory.py {% for ip in addresses %} {{ ip }} {% endfor %}
|
||||||
93
contrib/dind/run-test-distros.sh
Executable file
93
contrib/dind/run-test-distros.sh
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Q&D test'em all: creates full DIND kubespray deploys
|
||||||
|
# for each distro, verifying it via netchecker.
|
||||||
|
|
||||||
|
info() {
|
||||||
|
local msg="$*"
|
||||||
|
local date="$(date -Isec)"
|
||||||
|
echo "INFO: [$date] $msg"
|
||||||
|
}
|
||||||
|
pass_or_fail() {
|
||||||
|
local rc="$?"
|
||||||
|
local msg="$*"
|
||||||
|
local date="$(date -Isec)"
|
||||||
|
[ $rc -eq 0 ] && echo "PASS: [$date] $msg" || echo "FAIL: [$date] $msg"
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
test_distro() {
|
||||||
|
local distro=${1:?};shift
|
||||||
|
local extra="${*:-}"
|
||||||
|
local prefix="${distro[${extra}]}"
|
||||||
|
ansible-playbook -i hosts dind-cluster.yaml -e node_distro=$distro
|
||||||
|
pass_or_fail "$prefix: dind-nodes" || return 1
|
||||||
|
(cd ../..
|
||||||
|
INVENTORY_DIR=inventory/local-dind
|
||||||
|
mkdir -p ${INVENTORY_DIR}
|
||||||
|
rm -f ${INVENTORY_DIR}/hosts.ini
|
||||||
|
CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
||||||
|
# expand $extra with -e in front of each word
|
||||||
|
extra_args=""; for extra_arg in $extra; do extra_args="$extra_args -e $extra_arg"; done
|
||||||
|
ansible-playbook --become -e ansible_ssh_user=$distro -i \
|
||||||
|
${INVENTORY_DIR}/hosts.ini cluster.yml \
|
||||||
|
-e @contrib/dind/kubespray-dind.yaml -e bootstrap_os=$distro ${extra_args}
|
||||||
|
pass_or_fail "$prefix: kubespray"
|
||||||
|
) || return 1
|
||||||
|
local node0=${NODES[0]}
|
||||||
|
docker exec ${node0} kubectl get pod --all-namespaces
|
||||||
|
pass_or_fail "$prefix: kube-api" || return 1
|
||||||
|
let retries=60
|
||||||
|
while ((retries--)); do
|
||||||
|
# Some CNI may set NodePort on "main" node interface address (thus no localhost NodePort)
|
||||||
|
# e.g. kube-router: https://github.com/cloudnativelabs/kube-router/pull/217
|
||||||
|
docker exec ${node0} curl -m2 -s http://${NETCHECKER_HOST:?}:31081/api/v1/connectivity_check | grep successfully && break
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
[ $retries -ge 0 ]
|
||||||
|
pass_or_fail "$prefix: netcheck" || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
NODES=($(egrep ^kube_node hosts))
|
||||||
|
NETCHECKER_HOST=localhost
|
||||||
|
|
||||||
|
: ${OUTPUT_DIR:=./out}
|
||||||
|
mkdir -p ${OUTPUT_DIR}
|
||||||
|
|
||||||
|
# The SPEC file(s) must have two arrays as e.g.
|
||||||
|
# DISTROS=(debian centos)
|
||||||
|
# EXTRAS=(
|
||||||
|
# 'kube_network_plugin=calico'
|
||||||
|
# 'kube_network_plugin=flannel'
|
||||||
|
# 'kube_network_plugin=weave'
|
||||||
|
# )
|
||||||
|
# that will be tested in a "combinatory" way (e.g. from above there'll be
|
||||||
|
# be 6 test runs), creating a sequenced <spec_filename>-nn.out with each output.
|
||||||
|
#
|
||||||
|
# Each $EXTRAS element will be whitespace split, and passed as --extra-vars
|
||||||
|
# to main kubespray ansible-playbook run.
|
||||||
|
|
||||||
|
SPECS=${*:?Missing SPEC files, e.g. test-most_distros-some_CNIs.env}
|
||||||
|
for spec in ${SPECS}; do
|
||||||
|
unset DISTROS EXTRAS
|
||||||
|
echo "Loading file=${spec} ..."
|
||||||
|
. ${spec} || continue
|
||||||
|
: ${DISTROS:?} || continue
|
||||||
|
echo "DISTROS:" "${DISTROS[@]}"
|
||||||
|
echo "EXTRAS->"
|
||||||
|
printf " %s\n" "${EXTRAS[@]}"
|
||||||
|
let n=1
|
||||||
|
for distro in "${DISTROS[@]}"; do
|
||||||
|
for extra in "${EXTRAS[@]:-NULL}"; do
|
||||||
|
# Magic value to let this for run once:
|
||||||
|
[[ ${extra} == NULL ]] && unset extra
|
||||||
|
docker rm -f "${NODES[@]}"
|
||||||
|
printf -v file_out "%s/%s-%02d.out" ${OUTPUT_DIR} ${spec} $((n++))
|
||||||
|
{
|
||||||
|
info "${distro}[${extra}] START: file_out=${file_out}"
|
||||||
|
time test_distro ${distro} ${extra}
|
||||||
|
} |& tee ${file_out}
|
||||||
|
# sleeping for the sake of the human to verify if they want
|
||||||
|
sleep 2m
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
egrep -H '^(....:|real)' $(ls -tr ${OUTPUT_DIR}/*.out)
|
||||||
11
contrib/dind/test-most_distros-some_CNIs.env
Normal file
11
contrib/dind/test-most_distros-some_CNIs.env
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Test spec file: used from ./run-test-distros.sh, will run
|
||||||
|
# each distro in $DISTROS overloading main kubespray ansible-playbook run
|
||||||
|
# Get all DISTROS from distro.yaml (shame no yaml parsing, but nuff anyway)
|
||||||
|
# DISTROS="${*:-$(egrep -o '^ \w+' group_vars/all/distro.yaml|paste -s)}"
|
||||||
|
DISTROS=(debian ubuntu centos fedora)
|
||||||
|
|
||||||
|
# Each line below will be added as --extra-vars to main playbook run
|
||||||
|
EXTRAS=(
|
||||||
|
'kube_network_plugin=calico'
|
||||||
|
'kube_network_plugin=weave'
|
||||||
|
)
|
||||||
6
contrib/dind/test-some_distros-kube_router_combo.env
Normal file
6
contrib/dind/test-some_distros-kube_router_combo.env
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
DISTROS=(debian centos)
|
||||||
|
NETCHECKER_HOST=${NODES[0]}
|
||||||
|
EXTRAS=(
|
||||||
|
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":false}'
|
||||||
|
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":true}'
|
||||||
|
)
|
||||||
8
contrib/dind/test-some_distros-most_CNIs.env
Normal file
8
contrib/dind/test-some_distros-most_CNIs.env
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
DISTROS=(debian centos)
|
||||||
|
EXTRAS=(
|
||||||
|
'kube_network_plugin=calico {}'
|
||||||
|
'kube_network_plugin=canal {}'
|
||||||
|
'kube_network_plugin=cilium {}'
|
||||||
|
'kube_network_plugin=flannel {}'
|
||||||
|
'kube_network_plugin=weave {}'
|
||||||
|
)
|
||||||
480
contrib/inventory_builder/inventory.py
Normal file
480
contrib/inventory_builder/inventory.py
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# Usage: inventory.py ip1 [ip2 ...]
|
||||||
|
# Examples: inventory.py 10.10.1.3 10.10.1.4 10.10.1.5
|
||||||
|
#
|
||||||
|
# Advanced usage:
|
||||||
|
# Add another host after initial creation: inventory.py 10.10.1.5
|
||||||
|
# Add range of hosts: inventory.py 10.10.1.3-10.10.1.5
|
||||||
|
# Add hosts with different ip and access ip:
|
||||||
|
# inventory.py 10.0.0.1,192.168.10.1 10.0.0.2,192.168.10.2 10.0.0.3,192.168.1.3
|
||||||
|
# Add hosts with a specific hostname, ip, and optional access ip:
|
||||||
|
# inventory.py first,10.0.0.1,192.168.10.1 second,10.0.0.2 last,10.0.0.3
|
||||||
|
# Delete a host: inventory.py -10.10.1.3
|
||||||
|
# Delete a host by id: inventory.py -node1
|
||||||
|
#
|
||||||
|
# Load a YAML or JSON file with inventory data: inventory.py load hosts.yaml
|
||||||
|
# YAML file should be in the following format:
|
||||||
|
# group1:
|
||||||
|
# host1:
|
||||||
|
# ip: X.X.X.X
|
||||||
|
# var: val
|
||||||
|
# group2:
|
||||||
|
# host2:
|
||||||
|
# ip: X.X.X.X
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
from ipaddress import ip_address
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ROLES = ['all', 'kube_control_plane', 'kube_node', 'etcd', 'k8s_cluster',
|
||||||
|
'calico_rr']
|
||||||
|
PROTECTED_NAMES = ROLES
|
||||||
|
AVAILABLE_COMMANDS = ['help', 'print_cfg', 'print_ips', 'print_hostnames',
|
||||||
|
'load', 'add']
|
||||||
|
_boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
|
||||||
|
'0': False, 'no': False, 'false': False, 'off': False}
|
||||||
|
yaml = YAML()
|
||||||
|
yaml.Representer.add_representer(OrderedDict, yaml.Representer.represent_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def get_var_as_bool(name, default):
|
||||||
|
value = os.environ.get(name, '')
|
||||||
|
return _boolean_states.get(value.lower(), default)
|
||||||
|
|
||||||
|
# Configurable as shell vars start
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.yaml")
|
||||||
|
# Remove the reference of KUBE_MASTERS after some deprecation cycles.
|
||||||
|
KUBE_CONTROL_HOSTS = int(os.environ.get("KUBE_CONTROL_HOSTS",
|
||||||
|
os.environ.get("KUBE_MASTERS", 2)))
|
||||||
|
# Reconfigures cluster distribution at scale
|
||||||
|
SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 50))
|
||||||
|
MASSIVE_SCALE_THRESHOLD = int(os.environ.get("MASSIVE_SCALE_THRESHOLD", 200))
|
||||||
|
|
||||||
|
DEBUG = get_var_as_bool("DEBUG", True)
|
||||||
|
HOST_PREFIX = os.environ.get("HOST_PREFIX", "node")
|
||||||
|
USE_REAL_HOSTNAME = get_var_as_bool("USE_REAL_HOSTNAME", False)
|
||||||
|
|
||||||
|
# Configurable as shell vars end
|
||||||
|
|
||||||
|
|
||||||
|
class KubesprayInventory(object):
|
||||||
|
|
||||||
|
def __init__(self, changed_hosts=None, config_file=None):
|
||||||
|
self.config_file = config_file
|
||||||
|
self.yaml_config = {}
|
||||||
|
loadPreviousConfig = False
|
||||||
|
printHostnames = False
|
||||||
|
# See whether there are any commands to process
|
||||||
|
if changed_hosts and changed_hosts[0] in AVAILABLE_COMMANDS:
|
||||||
|
if changed_hosts[0] == "add":
|
||||||
|
loadPreviousConfig = True
|
||||||
|
changed_hosts = changed_hosts[1:]
|
||||||
|
elif changed_hosts[0] == "print_hostnames":
|
||||||
|
loadPreviousConfig = True
|
||||||
|
printHostnames = True
|
||||||
|
else:
|
||||||
|
self.parse_command(changed_hosts[0], changed_hosts[1:])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# If the user wants to remove a node, we need to load the config anyway
|
||||||
|
if changed_hosts and changed_hosts[0][0] == "-":
|
||||||
|
loadPreviousConfig = True
|
||||||
|
|
||||||
|
if self.config_file and loadPreviousConfig: # Load previous YAML file
|
||||||
|
try:
|
||||||
|
self.hosts_file = open(config_file, 'r')
|
||||||
|
self.yaml_config = yaml.load(self.hosts_file)
|
||||||
|
except OSError as e:
|
||||||
|
# I am assuming we are catching "cannot open file" exceptions
|
||||||
|
print(e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if printHostnames:
|
||||||
|
self.print_hostnames()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
self.ensure_required_groups(ROLES)
|
||||||
|
|
||||||
|
if changed_hosts:
|
||||||
|
changed_hosts = self.range2ips(changed_hosts)
|
||||||
|
self.hosts = self.build_hostnames(changed_hosts,
|
||||||
|
loadPreviousConfig)
|
||||||
|
self.purge_invalid_hosts(self.hosts.keys(), PROTECTED_NAMES)
|
||||||
|
self.set_all(self.hosts)
|
||||||
|
self.set_k8s_cluster()
|
||||||
|
etcd_hosts_count = 3 if len(self.hosts.keys()) >= 3 else 1
|
||||||
|
self.set_etcd(list(self.hosts.keys())[:etcd_hosts_count])
|
||||||
|
if len(self.hosts) >= SCALE_THRESHOLD:
|
||||||
|
self.set_kube_control_plane(list(self.hosts.keys())[
|
||||||
|
etcd_hosts_count:(etcd_hosts_count + KUBE_CONTROL_HOSTS)])
|
||||||
|
else:
|
||||||
|
self.set_kube_control_plane(
|
||||||
|
list(self.hosts.keys())[:KUBE_CONTROL_HOSTS])
|
||||||
|
self.set_kube_node(self.hosts.keys())
|
||||||
|
if len(self.hosts) >= SCALE_THRESHOLD:
|
||||||
|
self.set_calico_rr(list(self.hosts.keys())[:etcd_hosts_count])
|
||||||
|
else: # Show help if no options
|
||||||
|
self.show_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
self.write_config(self.config_file)
|
||||||
|
|
||||||
|
def write_config(self, config_file):
|
||||||
|
if config_file:
|
||||||
|
with open(self.config_file, 'w') as f:
|
||||||
|
yaml.dump(self.yaml_config, f)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("WARNING: Unable to save config. Make sure you set "
|
||||||
|
"CONFIG_FILE env var.")
|
||||||
|
|
||||||
|
def debug(self, msg):
|
||||||
|
if DEBUG:
|
||||||
|
print("DEBUG: {0}".format(msg))
|
||||||
|
|
||||||
|
def get_ip_from_opts(self, optstring):
|
||||||
|
if 'ip' in optstring:
|
||||||
|
return optstring['ip']
|
||||||
|
else:
|
||||||
|
raise ValueError("IP parameter not found in options")
|
||||||
|
|
||||||
|
def ensure_required_groups(self, groups):
|
||||||
|
for group in groups:
|
||||||
|
if group == 'all':
|
||||||
|
self.debug("Adding group {0}".format(group))
|
||||||
|
if group not in self.yaml_config:
|
||||||
|
all_dict = OrderedDict([('hosts', OrderedDict({})),
|
||||||
|
('children', OrderedDict({}))])
|
||||||
|
self.yaml_config = {'all': all_dict}
|
||||||
|
else:
|
||||||
|
self.debug("Adding group {0}".format(group))
|
||||||
|
if group not in self.yaml_config['all']['children']:
|
||||||
|
self.yaml_config['all']['children'][group] = {'hosts': {}}
|
||||||
|
|
||||||
|
def get_host_id(self, host):
|
||||||
|
'''Returns integer host ID (without padding) from a given hostname.'''
|
||||||
|
try:
|
||||||
|
short_hostname = host.split('.')[0]
|
||||||
|
return int(re.findall("\\d+$", short_hostname)[-1])
|
||||||
|
except IndexError:
|
||||||
|
raise ValueError("Host name must end in an integer")
|
||||||
|
|
||||||
|
# Keeps already specified hosts,
|
||||||
|
# and adds or removes the hosts provided as an argument
|
||||||
|
def build_hostnames(self, changed_hosts, loadPreviousConfig=False):
|
||||||
|
existing_hosts = OrderedDict()
|
||||||
|
highest_host_id = 0
|
||||||
|
# Load already existing hosts from the YAML
|
||||||
|
if loadPreviousConfig:
|
||||||
|
try:
|
||||||
|
for host in self.yaml_config['all']['hosts']:
|
||||||
|
# Read configuration of an existing host
|
||||||
|
hostConfig = self.yaml_config['all']['hosts'][host]
|
||||||
|
existing_hosts[host] = hostConfig
|
||||||
|
# If the existing host seems
|
||||||
|
# to have been created automatically, detect its ID
|
||||||
|
if host.startswith(HOST_PREFIX):
|
||||||
|
host_id = self.get_host_id(host)
|
||||||
|
if host_id > highest_host_id:
|
||||||
|
highest_host_id = host_id
|
||||||
|
except Exception as e:
|
||||||
|
# I am assuming we are catching automatically
|
||||||
|
# created hosts without IDs
|
||||||
|
print(e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# FIXME(mattymo): Fix condition where delete then add reuses highest id
|
||||||
|
next_host_id = highest_host_id + 1
|
||||||
|
next_host = ""
|
||||||
|
|
||||||
|
all_hosts = existing_hosts.copy()
|
||||||
|
for host in changed_hosts:
|
||||||
|
# Delete the host from config the hostname/IP has a "-" prefix
|
||||||
|
if host[0] == "-":
|
||||||
|
realhost = host[1:]
|
||||||
|
if self.exists_hostname(all_hosts, realhost):
|
||||||
|
self.debug("Marked {0} for deletion.".format(realhost))
|
||||||
|
all_hosts.pop(realhost)
|
||||||
|
elif self.exists_ip(all_hosts, realhost):
|
||||||
|
self.debug("Marked {0} for deletion.".format(realhost))
|
||||||
|
self.delete_host_by_ip(all_hosts, realhost)
|
||||||
|
# Host/Argument starts with a digit,
|
||||||
|
# then we assume its an IP address
|
||||||
|
elif host[0].isdigit():
|
||||||
|
if ',' in host:
|
||||||
|
ip, access_ip = host.split(',')
|
||||||
|
else:
|
||||||
|
ip = host
|
||||||
|
access_ip = host
|
||||||
|
if self.exists_hostname(all_hosts, host):
|
||||||
|
self.debug("Skipping existing host {0}.".format(host))
|
||||||
|
continue
|
||||||
|
elif self.exists_ip(all_hosts, ip):
|
||||||
|
self.debug("Skipping existing host {0}.".format(ip))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if USE_REAL_HOSTNAME:
|
||||||
|
cmd = ("ssh -oStrictHostKeyChecking=no "
|
||||||
|
+ access_ip + " 'hostname -s'")
|
||||||
|
next_host = subprocess.check_output(cmd, shell=True)
|
||||||
|
next_host = next_host.strip().decode('ascii')
|
||||||
|
else:
|
||||||
|
# Generates a hostname because we have only an IP address
|
||||||
|
next_host = "{0}{1}".format(HOST_PREFIX, next_host_id)
|
||||||
|
next_host_id += 1
|
||||||
|
# Uses automatically generated node name
|
||||||
|
# in case we dont provide it.
|
||||||
|
all_hosts[next_host] = {'ansible_host': access_ip,
|
||||||
|
'ip': ip,
|
||||||
|
'access_ip': access_ip}
|
||||||
|
# Host/Argument starts with a letter, then we assume its a hostname
|
||||||
|
elif host[0].isalpha():
|
||||||
|
if ',' in host:
|
||||||
|
try:
|
||||||
|
hostname, ip, access_ip = host.split(',')
|
||||||
|
except Exception:
|
||||||
|
hostname, ip = host.split(',')
|
||||||
|
access_ip = ip
|
||||||
|
if self.exists_hostname(all_hosts, host):
|
||||||
|
self.debug("Skipping existing host {0}.".format(host))
|
||||||
|
continue
|
||||||
|
elif self.exists_ip(all_hosts, ip):
|
||||||
|
self.debug("Skipping existing host {0}.".format(ip))
|
||||||
|
continue
|
||||||
|
all_hosts[hostname] = {'ansible_host': access_ip,
|
||||||
|
'ip': ip,
|
||||||
|
'access_ip': access_ip}
|
||||||
|
return all_hosts
|
||||||
|
|
||||||
|
# Expand IP ranges into individual addresses
|
||||||
|
def range2ips(self, hosts):
|
||||||
|
reworked_hosts = []
|
||||||
|
|
||||||
|
def ips(start_address, end_address):
|
||||||
|
try:
|
||||||
|
# Python 3.x
|
||||||
|
start = int(ip_address(start_address))
|
||||||
|
end = int(ip_address(end_address))
|
||||||
|
except Exception:
|
||||||
|
# Python 2.7
|
||||||
|
start = int(ip_address(str(start_address)))
|
||||||
|
end = int(ip_address(str(end_address)))
|
||||||
|
return [ip_address(ip).exploded for ip in range(start, end + 1)]
|
||||||
|
|
||||||
|
for host in hosts:
|
||||||
|
if '-' in host and not (host.startswith('-') or host[0].isalpha()):
|
||||||
|
start, end = host.strip().split('-')
|
||||||
|
try:
|
||||||
|
reworked_hosts.extend(ips(start, end))
|
||||||
|
except ValueError:
|
||||||
|
raise Exception("Range of ip_addresses isn't valid")
|
||||||
|
else:
|
||||||
|
reworked_hosts.append(host)
|
||||||
|
return reworked_hosts
|
||||||
|
|
||||||
|
def exists_hostname(self, existing_hosts, hostname):
|
||||||
|
return hostname in existing_hosts.keys()
|
||||||
|
|
||||||
|
def exists_ip(self, existing_hosts, ip):
|
||||||
|
for host_opts in existing_hosts.values():
|
||||||
|
if ip == self.get_ip_from_opts(host_opts):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_host_by_ip(self, existing_hosts, ip):
|
||||||
|
for hostname, host_opts in existing_hosts.items():
|
||||||
|
if ip == self.get_ip_from_opts(host_opts):
|
||||||
|
del existing_hosts[hostname]
|
||||||
|
return
|
||||||
|
raise ValueError("Unable to find host by IP: {0}".format(ip))
|
||||||
|
|
||||||
|
def purge_invalid_hosts(self, hostnames, protected_names=[]):
|
||||||
|
for role in self.yaml_config['all']['children']:
|
||||||
|
if role != 'k8s_cluster' and self.yaml_config['all']['children'][role]['hosts']: # noqa
|
||||||
|
all_hosts = self.yaml_config['all']['children'][role]['hosts'].copy() # noqa
|
||||||
|
for host in all_hosts.keys():
|
||||||
|
if host not in hostnames and host not in protected_names:
|
||||||
|
self.debug(
|
||||||
|
"Host {0} removed from role {1}".format(host, role)) # noqa
|
||||||
|
del self.yaml_config['all']['children'][role]['hosts'][host] # noqa
|
||||||
|
# purge from all
|
||||||
|
if self.yaml_config['all']['hosts']:
|
||||||
|
all_hosts = self.yaml_config['all']['hosts'].copy()
|
||||||
|
for host in all_hosts.keys():
|
||||||
|
if host not in hostnames and host not in protected_names:
|
||||||
|
self.debug("Host {0} removed from role all".format(host))
|
||||||
|
del self.yaml_config['all']['hosts'][host]
|
||||||
|
|
||||||
|
def add_host_to_group(self, group, host, opts=""):
|
||||||
|
self.debug("adding host {0} to group {1}".format(host, group))
|
||||||
|
if group == 'all':
|
||||||
|
if self.yaml_config['all']['hosts'] is None:
|
||||||
|
self.yaml_config['all']['hosts'] = {host: None}
|
||||||
|
self.yaml_config['all']['hosts'][host] = opts
|
||||||
|
elif group != 'k8s_cluster:children':
|
||||||
|
if self.yaml_config['all']['children'][group]['hosts'] is None:
|
||||||
|
self.yaml_config['all']['children'][group]['hosts'] = {
|
||||||
|
host: None}
|
||||||
|
else:
|
||||||
|
self.yaml_config['all']['children'][group]['hosts'][host] = None # noqa
|
||||||
|
|
||||||
|
def set_kube_control_plane(self, hosts):
|
||||||
|
for host in hosts:
|
||||||
|
self.add_host_to_group('kube_control_plane', host)
|
||||||
|
|
||||||
|
def set_all(self, hosts):
|
||||||
|
for host, opts in hosts.items():
|
||||||
|
self.add_host_to_group('all', host, opts)
|
||||||
|
|
||||||
|
def set_k8s_cluster(self):
|
||||||
|
k8s_cluster = {'children': {'kube_control_plane': None,
|
||||||
|
'kube_node': None}}
|
||||||
|
self.yaml_config['all']['children']['k8s_cluster'] = k8s_cluster
|
||||||
|
|
||||||
|
def set_calico_rr(self, hosts):
|
||||||
|
for host in hosts:
|
||||||
|
if host in self.yaml_config['all']['children']['kube_control_plane']: # noqa
|
||||||
|
self.debug("Not adding {0} to calico_rr group because it "
|
||||||
|
"conflicts with kube_control_plane "
|
||||||
|
"group".format(host))
|
||||||
|
continue
|
||||||
|
if host in self.yaml_config['all']['children']['kube_node']:
|
||||||
|
self.debug("Not adding {0} to calico_rr group because it "
|
||||||
|
"conflicts with kube_node group".format(host))
|
||||||
|
continue
|
||||||
|
self.add_host_to_group('calico_rr', host)
|
||||||
|
|
||||||
|
def set_kube_node(self, hosts):
|
||||||
|
for host in hosts:
|
||||||
|
if len(self.yaml_config['all']['hosts']) >= SCALE_THRESHOLD:
|
||||||
|
if host in self.yaml_config['all']['children']['etcd']['hosts']: # noqa
|
||||||
|
self.debug("Not adding {0} to kube_node group because of "
|
||||||
|
"scale deployment and host is in etcd "
|
||||||
|
"group.".format(host))
|
||||||
|
continue
|
||||||
|
if len(self.yaml_config['all']['hosts']) >= MASSIVE_SCALE_THRESHOLD: # noqa
|
||||||
|
if host in self.yaml_config['all']['children']['kube_control_plane']['hosts']: # noqa
|
||||||
|
self.debug("Not adding {0} to kube_node group because of "
|
||||||
|
"scale deployment and host is in "
|
||||||
|
"kube_control_plane group.".format(host))
|
||||||
|
continue
|
||||||
|
self.add_host_to_group('kube_node', host)
|
||||||
|
|
||||||
|
def set_etcd(self, hosts):
|
||||||
|
for host in hosts:
|
||||||
|
self.add_host_to_group('etcd', host)
|
||||||
|
|
||||||
|
def load_file(self, files=None):
|
||||||
|
'''Directly loads JSON to inventory.'''
|
||||||
|
|
||||||
|
if not files:
|
||||||
|
raise Exception("No input file specified.")
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
for filename in list(files):
|
||||||
|
# Try JSON
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except ValueError:
|
||||||
|
raise Exception("Cannot read %s as JSON, or CSV", filename)
|
||||||
|
|
||||||
|
self.ensure_required_groups(ROLES)
|
||||||
|
self.set_k8s_cluster()
|
||||||
|
for group, hosts in data.items():
|
||||||
|
self.ensure_required_groups([group])
|
||||||
|
for host, opts in hosts.items():
|
||||||
|
optstring = {'ansible_host': opts['ip'],
|
||||||
|
'ip': opts['ip'],
|
||||||
|
'access_ip': opts['ip']}
|
||||||
|
self.add_host_to_group('all', host, optstring)
|
||||||
|
self.add_host_to_group(group, host)
|
||||||
|
self.write_config(self.config_file)
|
||||||
|
|
||||||
|
def parse_command(self, command, args=None):
|
||||||
|
if command == 'help':
|
||||||
|
self.show_help()
|
||||||
|
elif command == 'print_cfg':
|
||||||
|
self.print_config()
|
||||||
|
elif command == 'print_ips':
|
||||||
|
self.print_ips()
|
||||||
|
elif command == 'print_hostnames':
|
||||||
|
self.print_hostnames()
|
||||||
|
elif command == 'load':
|
||||||
|
self.load_file(args)
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid command specified.")
|
||||||
|
|
||||||
|
def show_help(self):
|
||||||
|
help_text = '''Usage: inventory.py ip1 [ip2 ...]
|
||||||
|
Examples: inventory.py 10.10.1.3 10.10.1.4 10.10.1.5
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
help - Display this message
|
||||||
|
print_cfg - Write inventory file to stdout
|
||||||
|
print_ips - Write a space-delimited list of IPs from "all" group
|
||||||
|
print_hostnames - Write a space-delimited list of Hostnames from "all" group
|
||||||
|
add - Adds specified hosts into an already existing inventory
|
||||||
|
|
||||||
|
Advanced usage:
|
||||||
|
Create new or overwrite old inventory file: inventory.py 10.10.1.5
|
||||||
|
Add another host after initial creation: inventory.py add 10.10.1.6
|
||||||
|
Add range of hosts: inventory.py 10.10.1.3-10.10.1.5
|
||||||
|
Add hosts with different ip and access ip: inventory.py 10.0.0.1,192.168.10.1 10.0.0.2,192.168.10.2 10.0.0.3,192.168.10.3
|
||||||
|
Add hosts with a specific hostname, ip, and optional access ip: first,10.0.0.1,192.168.10.1 second,10.0.0.2 last,10.0.0.3
|
||||||
|
Delete a host: inventory.py -10.10.1.3
|
||||||
|
Delete a host by id: inventory.py -node1
|
||||||
|
|
||||||
|
Configurable env vars:
|
||||||
|
DEBUG Enable debug printing. Default: True
|
||||||
|
CONFIG_FILE File to write config to Default: ./inventory/sample/hosts.yaml
|
||||||
|
HOST_PREFIX Host prefix for generated hosts. Default: node
|
||||||
|
KUBE_CONTROL_HOSTS Set the number of kube-control-planes. Default: 2
|
||||||
|
SCALE_THRESHOLD Separate ETCD role if # of nodes >= 50
|
||||||
|
MASSIVE_SCALE_THRESHOLD Separate K8s control-plane and ETCD if # of nodes >= 200
|
||||||
|
''' # noqa
|
||||||
|
print(help_text)
|
||||||
|
|
||||||
|
def print_config(self):
|
||||||
|
yaml.dump(self.yaml_config, sys.stdout)
|
||||||
|
|
||||||
|
def print_hostnames(self):
|
||||||
|
print(' '.join(self.yaml_config['all']['hosts'].keys()))
|
||||||
|
|
||||||
|
def print_ips(self):
|
||||||
|
ips = []
|
||||||
|
for host, opts in self.yaml_config['all']['hosts'].items():
|
||||||
|
ips.append(self.get_ip_from_opts(opts))
|
||||||
|
print(' '.join(ips))
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
if not argv:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
KubesprayInventory(argv, CONFIG_FILE)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
3
contrib/inventory_builder/requirements.txt
Normal file
3
contrib/inventory_builder/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
configparser>=3.3.0
|
||||||
|
ipaddress
|
||||||
|
ruamel.yaml>=0.15.88
|
||||||
3
contrib/inventory_builder/setup.cfg
Normal file
3
contrib/inventory_builder/setup.cfg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[metadata]
|
||||||
|
name = kubespray-inventory-builder
|
||||||
|
version = 0.1
|
||||||
29
contrib/inventory_builder/setup.py
Normal file
29
contrib/inventory_builder/setup.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||||
|
# setuptools if some other modules registered functions in `atexit`.
|
||||||
|
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||||
|
try:
|
||||||
|
import multiprocessing # noqa
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=[],
|
||||||
|
pbr=False)
|
||||||
3
contrib/inventory_builder/test-requirements.txt
Normal file
3
contrib/inventory_builder/test-requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
hacking>=0.10.2
|
||||||
|
mock>=1.3.0
|
||||||
|
pytest>=2.8.0
|
||||||
595
contrib/inventory_builder/tests/test_inventory.py
Normal file
595
contrib/inventory_builder/tests/test_inventory.py
Normal file
@@ -0,0 +1,595 @@
|
|||||||
|
# Copyright 2016 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import inventory
|
||||||
|
from io import StringIO
|
||||||
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
import sys
|
||||||
|
|
||||||
|
path = "./contrib/inventory_builder/"
|
||||||
|
if path not in sys.path:
|
||||||
|
sys.path.append(path)
|
||||||
|
|
||||||
|
import inventory # noqa
|
||||||
|
|
||||||
|
|
||||||
|
class TestInventoryPrintHostnames(unittest.TestCase):
|
||||||
|
|
||||||
|
@mock.patch('ruamel.yaml.YAML.load')
|
||||||
|
def test_print_hostnames(self, load_mock):
|
||||||
|
mock_io = mock.mock_open(read_data='')
|
||||||
|
load_mock.return_value = OrderedDict({'all': {'hosts': {
|
||||||
|
'node1': {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'},
|
||||||
|
'node2': {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'}}}})
|
||||||
|
with mock.patch('builtins.open', mock_io):
|
||||||
|
with self.assertRaises(SystemExit) as cm:
|
||||||
|
with mock.patch('sys.stdout', new_callable=StringIO) as stdout:
|
||||||
|
inventory.KubesprayInventory(
|
||||||
|
changed_hosts=["print_hostnames"],
|
||||||
|
config_file="file")
|
||||||
|
self.assertEqual("node1 node2\n", stdout.getvalue())
|
||||||
|
self.assertEqual(cm.exception.code, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestInventory(unittest.TestCase):
|
||||||
|
@mock.patch('inventory.sys')
|
||||||
|
def setUp(self, sys_mock):
|
||||||
|
sys_mock.exit = mock.Mock()
|
||||||
|
super(TestInventory, self).setUp()
|
||||||
|
self.data = ['10.90.3.2', '10.90.3.3', '10.90.3.4']
|
||||||
|
self.inv = inventory.KubesprayInventory()
|
||||||
|
|
||||||
|
def test_get_ip_from_opts(self):
|
||||||
|
optstring = {'ansible_host': '10.90.3.2',
|
||||||
|
'ip': '10.90.3.2',
|
||||||
|
'access_ip': '10.90.3.2'}
|
||||||
|
expected = "10.90.3.2"
|
||||||
|
result = self.inv.get_ip_from_opts(optstring)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_get_ip_from_opts_invalid(self):
|
||||||
|
optstring = "notanaddr=value something random!chars:D"
|
||||||
|
self.assertRaisesRegex(ValueError, "IP parameter not found",
|
||||||
|
self.inv.get_ip_from_opts, optstring)
|
||||||
|
|
||||||
|
def test_ensure_required_groups(self):
|
||||||
|
groups = ['group1', 'group2']
|
||||||
|
self.inv.ensure_required_groups(groups)
|
||||||
|
for group in groups:
|
||||||
|
self.assertIn(group, self.inv.yaml_config['all']['children'])
|
||||||
|
|
||||||
|
def test_get_host_id(self):
|
||||||
|
hostnames = ['node99', 'no99de01', '01node01', 'node1.domain',
|
||||||
|
'node3.xyz123.aaa']
|
||||||
|
expected = [99, 1, 1, 1, 3]
|
||||||
|
for hostname, expected in zip(hostnames, expected):
|
||||||
|
result = self.inv.get_host_id(hostname)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_get_host_id_invalid(self):
|
||||||
|
bad_hostnames = ['node', 'no99de', '01node', 'node.111111']
|
||||||
|
for hostname in bad_hostnames:
|
||||||
|
self.assertRaisesRegex(ValueError, "Host name must end in an",
|
||||||
|
self.inv.get_host_id, hostname)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_duplicate(self):
|
||||||
|
changed_hosts = ['10.90.0.2']
|
||||||
|
expected = OrderedDict([('node3',
|
||||||
|
{'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = expected
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_two(self):
|
||||||
|
changed_hosts = ['10.90.0.2', '10.90.0.3']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = OrderedDict()
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_three(self):
|
||||||
|
changed_hosts = ['10.90.0.2', '10.90.0.3', '10.90.0.4']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'}),
|
||||||
|
('node3', {'ansible_host': '10.90.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '10.90.0.4'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_one(self):
|
||||||
|
changed_hosts = ['10.90.0.2']
|
||||||
|
expected = OrderedDict([('node1',
|
||||||
|
{'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_delete_first(self):
|
||||||
|
changed_hosts = ['-10.90.0.2']
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing_hosts
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_delete_by_hostname(self):
|
||||||
|
changed_hosts = ['-node1']
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing_hosts
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_exists_hostname_positive(self):
|
||||||
|
hostname = 'node1'
|
||||||
|
expected = True
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.exists_hostname(existing_hosts, hostname)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_exists_hostname_negative(self):
|
||||||
|
hostname = 'node99'
|
||||||
|
expected = False
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.exists_hostname(existing_hosts, hostname)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_exists_ip_positive(self):
|
||||||
|
ip = '10.90.0.2'
|
||||||
|
expected = True
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.exists_ip(existing_hosts, ip)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_exists_ip_negative(self):
|
||||||
|
ip = '10.90.0.200'
|
||||||
|
expected = False
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
result = self.inv.exists_ip(existing_hosts, ip)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_delete_host_by_ip_positive(self):
|
||||||
|
ip = '10.90.0.2'
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
self.inv.delete_host_by_ip(existing_hosts, ip)
|
||||||
|
self.assertEqual(expected, existing_hosts)
|
||||||
|
|
||||||
|
def test_delete_host_by_ip_negative(self):
|
||||||
|
ip = '10.90.0.200'
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'})])
|
||||||
|
self.assertRaisesRegex(ValueError, "Unable to find host",
|
||||||
|
self.inv.delete_host_by_ip, existing_hosts, ip)
|
||||||
|
|
||||||
|
def test_purge_invalid_hosts(self):
|
||||||
|
proper_hostnames = ['node1', 'node2']
|
||||||
|
bad_host = 'doesnotbelong2'
|
||||||
|
existing_hosts = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '10.90.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '10.90.0.2'}),
|
||||||
|
('node2', {'ansible_host': '10.90.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '10.90.0.3'}),
|
||||||
|
('doesnotbelong2', {'whateveropts=ilike'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing_hosts
|
||||||
|
self.inv.purge_invalid_hosts(proper_hostnames)
|
||||||
|
self.assertNotIn(
|
||||||
|
bad_host, self.inv.yaml_config['all']['hosts'].keys())
|
||||||
|
|
||||||
|
def test_add_host_to_group(self):
|
||||||
|
group = 'etcd'
|
||||||
|
host = 'node1'
|
||||||
|
opts = {'ip': '10.90.0.2'}
|
||||||
|
|
||||||
|
self.inv.add_host_to_group(group, host, opts)
|
||||||
|
self.assertEqual(
|
||||||
|
self.inv.yaml_config['all']['children'][group]['hosts'].get(host),
|
||||||
|
None)
|
||||||
|
|
||||||
|
def test_set_kube_control_plane(self):
|
||||||
|
group = 'kube_control_plane'
|
||||||
|
host = 'node1'
|
||||||
|
|
||||||
|
self.inv.set_kube_control_plane([host])
|
||||||
|
self.assertIn(
|
||||||
|
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
||||||
|
|
||||||
|
def test_set_all(self):
|
||||||
|
hosts = OrderedDict([
|
||||||
|
('node1', 'opt1'),
|
||||||
|
('node2', 'opt2')])
|
||||||
|
|
||||||
|
self.inv.set_all(hosts)
|
||||||
|
for host, opt in hosts.items():
|
||||||
|
self.assertEqual(
|
||||||
|
self.inv.yaml_config['all']['hosts'].get(host), opt)
|
||||||
|
|
||||||
|
def test_set_k8s_cluster(self):
|
||||||
|
group = 'k8s_cluster'
|
||||||
|
expected_hosts = ['kube_node', 'kube_control_plane']
|
||||||
|
|
||||||
|
self.inv.set_k8s_cluster()
|
||||||
|
for host in expected_hosts:
|
||||||
|
self.assertIn(
|
||||||
|
host,
|
||||||
|
self.inv.yaml_config['all']['children'][group]['children'])
|
||||||
|
|
||||||
|
def test_set_kube_node(self):
|
||||||
|
group = 'kube_node'
|
||||||
|
host = 'node1'
|
||||||
|
|
||||||
|
self.inv.set_kube_node([host])
|
||||||
|
self.assertIn(
|
||||||
|
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
||||||
|
|
||||||
|
def test_set_etcd(self):
|
||||||
|
group = 'etcd'
|
||||||
|
host = 'node1'
|
||||||
|
|
||||||
|
self.inv.set_etcd([host])
|
||||||
|
self.assertIn(
|
||||||
|
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
||||||
|
|
||||||
|
def test_scale_scenario_one(self):
|
||||||
|
num_nodes = 50
|
||||||
|
hosts = OrderedDict()
|
||||||
|
|
||||||
|
for hostid in range(1, num_nodes+1):
|
||||||
|
hosts["node" + str(hostid)] = ""
|
||||||
|
|
||||||
|
self.inv.set_all(hosts)
|
||||||
|
self.inv.set_etcd(list(hosts.keys())[0:3])
|
||||||
|
self.inv.set_kube_control_plane(list(hosts.keys())[0:2])
|
||||||
|
self.inv.set_kube_node(hosts.keys())
|
||||||
|
for h in range(3):
|
||||||
|
self.assertFalse(
|
||||||
|
list(hosts.keys())[h] in
|
||||||
|
self.inv.yaml_config['all']['children']['kube_node']['hosts'])
|
||||||
|
|
||||||
|
def test_scale_scenario_two(self):
|
||||||
|
num_nodes = 500
|
||||||
|
hosts = OrderedDict()
|
||||||
|
|
||||||
|
for hostid in range(1, num_nodes+1):
|
||||||
|
hosts["node" + str(hostid)] = ""
|
||||||
|
|
||||||
|
self.inv.set_all(hosts)
|
||||||
|
self.inv.set_etcd(list(hosts.keys())[0:3])
|
||||||
|
self.inv.set_kube_control_plane(list(hosts.keys())[3:5])
|
||||||
|
self.inv.set_kube_node(hosts.keys())
|
||||||
|
for h in range(5):
|
||||||
|
self.assertFalse(
|
||||||
|
list(hosts.keys())[h] in
|
||||||
|
self.inv.yaml_config['all']['children']['kube_node']['hosts'])
|
||||||
|
|
||||||
|
def test_range2ips_range(self):
|
||||||
|
changed_hosts = ['10.90.0.2', '10.90.0.4-10.90.0.6', '10.90.0.8']
|
||||||
|
expected = ['10.90.0.2',
|
||||||
|
'10.90.0.4',
|
||||||
|
'10.90.0.5',
|
||||||
|
'10.90.0.6',
|
||||||
|
'10.90.0.8']
|
||||||
|
result = self.inv.range2ips(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_range2ips_incorrect_range(self):
|
||||||
|
host_range = ['10.90.0.4-a.9b.c.e']
|
||||||
|
self.assertRaisesRegex(Exception, "Range of ip_addresses isn't valid",
|
||||||
|
self.inv.range2ips, host_range)
|
||||||
|
|
||||||
|
def test_build_hostnames_create_with_one_different_ips(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2']
|
||||||
|
expected = OrderedDict([('node1',
|
||||||
|
{'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_create_with_two_different_ips(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2', '10.90.0.3,192.168.0.3']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node2', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_create_with_three_different_ips(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2',
|
||||||
|
'10.90.0.3,192.168.0.3',
|
||||||
|
'10.90.0.4,192.168.0.4']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node1', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node2', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_overwrite_one_with_different_ips(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2']
|
||||||
|
expected = OrderedDict([('node1',
|
||||||
|
{'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'})])
|
||||||
|
existing = OrderedDict([('node5',
|
||||||
|
{'ansible_host': '192.168.0.5',
|
||||||
|
'ip': '10.90.0.5',
|
||||||
|
'access_ip': '192.168.0.5'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_overwrite_three_with_different_ips(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2']
|
||||||
|
expected = OrderedDict([('node1',
|
||||||
|
{'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'})])
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'}),
|
||||||
|
('node5', {'ansible_host': '192.168.0.5',
|
||||||
|
'ip': '10.90.0.5',
|
||||||
|
'access_ip': '192.168.0.5'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_different_ips_add_duplicate(self):
|
||||||
|
changed_hosts = ['10.90.0.2,192.168.0.2']
|
||||||
|
expected = OrderedDict([('node3',
|
||||||
|
{'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'})])
|
||||||
|
existing = expected
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_two_different_ips_into_one_existing(self):
|
||||||
|
changed_hosts = ['10.90.0.3,192.168.0.3', '10.90.0.4,192.168.0.4']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_two_different_ips_into_two_existing(self):
|
||||||
|
changed_hosts = ['10.90.0.4,192.168.0.4', '10.90.0.5,192.168.0.5']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'}),
|
||||||
|
('node5', {'ansible_host': '192.168.0.5',
|
||||||
|
'ip': '10.90.0.5',
|
||||||
|
'access_ip': '192.168.0.5'})])
|
||||||
|
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def test_build_hostnames_add_two_different_ips_into_three_existing(self):
|
||||||
|
changed_hosts = ['10.90.0.5,192.168.0.5', '10.90.0.6,192.168.0.6']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'}),
|
||||||
|
('node5', {'ansible_host': '192.168.0.5',
|
||||||
|
'ip': '10.90.0.5',
|
||||||
|
'access_ip': '192.168.0.5'}),
|
||||||
|
('node6', {'ansible_host': '192.168.0.6',
|
||||||
|
'ip': '10.90.0.6',
|
||||||
|
'access_ip': '192.168.0.6'})])
|
||||||
|
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
# Add two IP addresses into a config that has
|
||||||
|
# three already defined IP addresses. One of the IP addresses
|
||||||
|
# is a duplicate.
|
||||||
|
def test_build_hostnames_add_two_duplicate_one_overlap(self):
|
||||||
|
changed_hosts = ['10.90.0.4,192.168.0.4', '10.90.0.5,192.168.0.5']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'}),
|
||||||
|
('node5', {'ansible_host': '192.168.0.5',
|
||||||
|
'ip': '10.90.0.5',
|
||||||
|
'access_ip': '192.168.0.5'})])
|
||||||
|
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
# Add two duplicate IP addresses into a config that has
|
||||||
|
# three already defined IP addresses
|
||||||
|
def test_build_hostnames_add_two_duplicate_two_overlap(self):
|
||||||
|
changed_hosts = ['10.90.0.3,192.168.0.3', '10.90.0.4,192.168.0.4']
|
||||||
|
expected = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
|
||||||
|
existing = OrderedDict([
|
||||||
|
('node2', {'ansible_host': '192.168.0.2',
|
||||||
|
'ip': '10.90.0.2',
|
||||||
|
'access_ip': '192.168.0.2'}),
|
||||||
|
('node3', {'ansible_host': '192.168.0.3',
|
||||||
|
'ip': '10.90.0.3',
|
||||||
|
'access_ip': '192.168.0.3'}),
|
||||||
|
('node4', {'ansible_host': '192.168.0.4',
|
||||||
|
'ip': '10.90.0.4',
|
||||||
|
'access_ip': '192.168.0.4'})])
|
||||||
|
self.inv.yaml_config['all']['hosts'] = existing
|
||||||
|
result = self.inv.build_hostnames(changed_hosts, True)
|
||||||
|
self.assertEqual(expected, result)
|
||||||
34
contrib/inventory_builder/tox.ini
Normal file
34
contrib/inventory_builder/tox.ini
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[tox]
|
||||||
|
minversion = 1.6
|
||||||
|
skipsdist = True
|
||||||
|
envlist = pep8
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
allowlist_externals = py.test
|
||||||
|
usedevelop = True
|
||||||
|
deps =
|
||||||
|
-r{toxinidir}/requirements.txt
|
||||||
|
-r{toxinidir}/test-requirements.txt
|
||||||
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
|
passenv =
|
||||||
|
http_proxy
|
||||||
|
HTTP_PROXY
|
||||||
|
https_proxy
|
||||||
|
HTTPS_PROXY
|
||||||
|
no_proxy
|
||||||
|
NO_PROXY
|
||||||
|
commands = pytest -vv #{posargs:./tests}
|
||||||
|
|
||||||
|
[testenv:pep8]
|
||||||
|
usedevelop = False
|
||||||
|
allowlist_externals = bash
|
||||||
|
commands =
|
||||||
|
bash -c "find {toxinidir}/* -type f -name '*.py' -print0 | xargs -0 flake8"
|
||||||
|
|
||||||
|
[testenv:venv]
|
||||||
|
commands = {posargs}
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
show-source = true
|
||||||
|
builtins = _
|
||||||
|
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
- name: Prepare Hypervisor to later install kubespray VMs
|
- name: Prepare Hypervisor to later install kubespray VMs
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
gather_facts: false
|
gather_facts: False
|
||||||
become: true
|
become: yes
|
||||||
vars:
|
vars:
|
||||||
bootstrap_os: none
|
bootstrap_os: none
|
||||||
roles:
|
roles:
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
- name: Install required packages
|
- name: Install required packages
|
||||||
apt:
|
apt:
|
||||||
upgrade: true
|
upgrade: yes
|
||||||
update_cache: true
|
update_cache: yes
|
||||||
cache_valid_time: 3600
|
cache_valid_time: 3600
|
||||||
name: "{{ item }}"
|
name: "{{ item }}"
|
||||||
state: present
|
state: present
|
||||||
install_recommends: false
|
install_recommends: no
|
||||||
with_items:
|
with_items:
|
||||||
- dnsutils
|
- dnsutils
|
||||||
- ntp
|
- ntp
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
br-netfilter
|
br-netfilter
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
when: br_netfilter is defined
|
when: br_netfilter is defined
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
value: 1
|
value: 1
|
||||||
sysctl_file: "{{ sysctl_file_path }}"
|
sysctl_file: "{{ sysctl_file_path }}"
|
||||||
state: present
|
state: present
|
||||||
reload: true
|
reload: yes
|
||||||
|
|
||||||
- name: Set bridge-nf-call-{arptables,iptables} to 0
|
- name: Set bridge-nf-call-{arptables,iptables} to 0
|
||||||
ansible.posix.sysctl:
|
ansible.posix.sysctl:
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
state: present
|
state: present
|
||||||
value: 0
|
value: 0
|
||||||
sysctl_file: "{{ sysctl_file_path }}"
|
sysctl_file: "{{ sysctl_file_path }}"
|
||||||
reload: true
|
reload: yes
|
||||||
with_items:
|
with_items:
|
||||||
- net.bridge.bridge-nf-call-arptables
|
- net.bridge.bridge-nf-call-arptables
|
||||||
- net.bridge.bridge-nf-call-ip6tables
|
- net.bridge.bridge-nf-call-ip6tables
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
state: directory
|
state: directory
|
||||||
owner: "{{ k8s_deployment_user }}"
|
owner: "{{ k8s_deployment_user }}"
|
||||||
group: "{{ k8s_deployment_user }}"
|
group: "{{ k8s_deployment_user }}"
|
||||||
mode: "0700"
|
mode: 0700
|
||||||
|
|
||||||
- name: Configure sudo for deployment user
|
- name: Configure sudo for deployment user
|
||||||
copy:
|
copy:
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
dest: "/etc/sudoers.d/55-k8s-deployment"
|
dest: "/etc/sudoers.d/55-k8s-deployment"
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|
||||||
- name: Write private SSH key
|
- name: Write private SSH key
|
||||||
copy:
|
copy:
|
||||||
src: "{{ k8s_deployment_user_pkey_path }}"
|
src: "{{ k8s_deployment_user_pkey_path }}"
|
||||||
dest: "/home/{{ k8s_deployment_user }}/.ssh/id_rsa"
|
dest: "/home/{{ k8s_deployment_user }}/.ssh/id_rsa"
|
||||||
mode: "0400"
|
mode: 0400
|
||||||
owner: "{{ k8s_deployment_user }}"
|
owner: "{{ k8s_deployment_user }}"
|
||||||
group: "{{ k8s_deployment_user }}"
|
group: "{{ k8s_deployment_user }}"
|
||||||
when: k8s_deployment_user_pkey_path is defined
|
when: k8s_deployment_user_pkey_path is defined
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
- name: Fix ssh-pub-key permissions
|
- name: Fix ssh-pub-key permissions
|
||||||
file:
|
file:
|
||||||
path: "/home/{{ k8s_deployment_user }}/.ssh/authorized_keys"
|
path: "/home/{{ k8s_deployment_user }}/.ssh/authorized_keys"
|
||||||
mode: "0600"
|
mode: 0600
|
||||||
owner: "{{ k8s_deployment_user }}"
|
owner: "{{ k8s_deployment_user }}"
|
||||||
group: "{{ k8s_deployment_user }}"
|
group: "{{ k8s_deployment_user }}"
|
||||||
when: k8s_deployment_user_pkey_path is defined
|
when: k8s_deployment_user_pkey_path is defined
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
file:
|
file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: "0755"
|
mode: 0755
|
||||||
become: false
|
become: false
|
||||||
loop:
|
loop:
|
||||||
- "{{ playbook_dir }}/plugins/mitogen"
|
- "{{ playbook_dir }}/plugins/mitogen"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
url: "{{ mitogen_url }}"
|
url: "{{ mitogen_url }}"
|
||||||
dest: "{{ playbook_dir }}/dist/mitogen_{{ mitogen_version }}.tar.gz"
|
dest: "{{ playbook_dir }}/dist/mitogen_{{ mitogen_version }}.tar.gz"
|
||||||
validate_certs: true
|
validate_certs: true
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|
||||||
- name: Extract archive
|
- name: Extract archive
|
||||||
unarchive:
|
unarchive:
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
- name: Add strategy to ansible.cfg
|
- name: Add strategy to ansible.cfg
|
||||||
community.general.ini_file:
|
community.general.ini_file:
|
||||||
path: ansible.cfg
|
path: ansible.cfg
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
section: "{{ item.section | d('defaults') }}"
|
section: "{{ item.section | d('defaults') }}"
|
||||||
option: "{{ item.option }}"
|
option: "{{ item.option }}"
|
||||||
value: "{{ item.value }}"
|
value: "{{ item.value }}"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ glusterfs_default_release: ""
|
|||||||
You can specify a `default_release` for apt on Debian/Ubuntu by overriding this variable. This is helpful if you need a different package or version for the main GlusterFS packages (e.g. GlusterFS 3.5.x instead of 3.2.x with the `wheezy-backports` default release on Debian Wheezy).
|
You can specify a `default_release` for apt on Debian/Ubuntu by overriding this variable. This is helpful if you need a different package or version for the main GlusterFS packages (e.g. GlusterFS 3.5.x instead of 3.2.x with the `wheezy-backports` default release on Debian Wheezy).
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
glusterfs_ppa_use: true
|
glusterfs_ppa_use: yes
|
||||||
glusterfs_ppa_version: "3.5"
|
glusterfs_ppa_version: "3.5"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
# For Ubuntu.
|
# For Ubuntu.
|
||||||
glusterfs_default_release: ""
|
glusterfs_default_release: ""
|
||||||
glusterfs_ppa_use: true
|
glusterfs_ppa_use: yes
|
||||||
glusterfs_ppa_version: "4.1"
|
glusterfs_ppa_version: "4.1"
|
||||||
|
|
||||||
# Gluster configuration.
|
# Gluster configuration.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
file:
|
file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: "0775"
|
mode: 0775
|
||||||
with_items:
|
with_items:
|
||||||
- "{{ gluster_mount_dir }}"
|
- "{{ gluster_mount_dir }}"
|
||||||
when: ansible_os_family in ["Debian","RedHat"] and groups['gfs-cluster'] is defined
|
when: ansible_os_family in ["Debian","RedHat"] and groups['gfs-cluster'] is defined
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
apt_repository:
|
apt_repository:
|
||||||
repo: 'ppa:gluster/glusterfs-{{ glusterfs_ppa_version }}'
|
repo: 'ppa:gluster/glusterfs-{{ glusterfs_ppa_version }}'
|
||||||
state: present
|
state: present
|
||||||
update_cache: true
|
update_cache: yes
|
||||||
register: glusterfs_ppa_added
|
register: glusterfs_ppa_added
|
||||||
when: glusterfs_ppa_use
|
when: glusterfs_ppa_use
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
# For Ubuntu.
|
# For Ubuntu.
|
||||||
glusterfs_default_release: ""
|
glusterfs_default_release: ""
|
||||||
glusterfs_ppa_use: true
|
glusterfs_ppa_use: yes
|
||||||
glusterfs_ppa_version: "3.12"
|
glusterfs_ppa_version: "3.12"
|
||||||
|
|
||||||
# Gluster configuration.
|
# Gluster configuration.
|
||||||
|
|||||||
@@ -43,13 +43,13 @@
|
|||||||
service:
|
service:
|
||||||
name: "{{ glusterfs_daemon }}"
|
name: "{{ glusterfs_daemon }}"
|
||||||
state: started
|
state: started
|
||||||
enabled: true
|
enabled: yes
|
||||||
|
|
||||||
- name: Ensure Gluster brick and mount directories exist.
|
- name: Ensure Gluster brick and mount directories exist.
|
||||||
file:
|
file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: "0775"
|
mode: 0775
|
||||||
with_items:
|
with_items:
|
||||||
- "{{ gluster_brick_dir }}"
|
- "{{ gluster_brick_dir }}"
|
||||||
- "{{ gluster_mount_dir }}"
|
- "{{ gluster_mount_dir }}"
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
replicas: "{{ groups['gfs-cluster'] | length }}"
|
replicas: "{{ groups['gfs-cluster'] | length }}"
|
||||||
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip'] | default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
|
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip'] | default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
|
||||||
host: "{{ inventory_hostname }}"
|
host: "{{ inventory_hostname }}"
|
||||||
force: true
|
force: yes
|
||||||
run_once: true
|
run_once: true
|
||||||
when: groups['gfs-cluster'] | length > 1
|
when: groups['gfs-cluster'] | length > 1
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
brick: "{{ gluster_brick_dir }}"
|
brick: "{{ gluster_brick_dir }}"
|
||||||
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip'] | default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
|
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip'] | default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
|
||||||
host: "{{ inventory_hostname }}"
|
host: "{{ inventory_hostname }}"
|
||||||
force: true
|
force: yes
|
||||||
run_once: true
|
run_once: true
|
||||||
when: groups['gfs-cluster'] | length <= 1
|
when: groups['gfs-cluster'] | length <= 1
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
template:
|
template:
|
||||||
dest: "{{ gluster_mount_dir }}/.test-file.txt"
|
dest: "{{ gluster_mount_dir }}/.test-file.txt"
|
||||||
src: test-file.txt
|
src: test-file.txt
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0]
|
when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0]
|
||||||
|
|
||||||
- name: Unmount glusterfs
|
- name: Unmount glusterfs
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
apt_repository:
|
apt_repository:
|
||||||
repo: 'ppa:gluster/glusterfs-{{ glusterfs_ppa_version }}'
|
repo: 'ppa:gluster/glusterfs-{{ glusterfs_ppa_version }}'
|
||||||
state: present
|
state: present
|
||||||
update_cache: true
|
update_cache: yes
|
||||||
register: glusterfs_ppa_added
|
register: glusterfs_ppa_added
|
||||||
when: glusterfs_ppa_use
|
when: glusterfs_ppa_use
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "{{ item.file }}"
|
src: "{{ item.file }}"
|
||||||
dest: "{{ kube_config_dir }}/{{ item.dest }}"
|
dest: "{{ kube_config_dir }}/{{ item.dest }}"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
with_items:
|
with_items:
|
||||||
- { file: glusterfs-kubernetes-endpoint.json.j2, type: ep, dest: glusterfs-kubernetes-endpoint.json}
|
- { file: glusterfs-kubernetes-endpoint.json.j2, type: ep, dest: glusterfs-kubernetes-endpoint.json}
|
||||||
- { file: glusterfs-kubernetes-pv.yml.j2, type: pv, dest: glusterfs-kubernetes-pv.yml}
|
- { file: glusterfs-kubernetes-pv.yml.j2, type: pv, dest: glusterfs-kubernetes-pv.yml}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
|
|
||||||
- name: Teardown disks in heketi
|
- name: Teardown disks in heketi
|
||||||
hosts: heketi-node
|
hosts: heketi-node
|
||||||
become: true
|
become: yes
|
||||||
roles:
|
roles:
|
||||||
- { role: tear-down-disks }
|
- { role: tear-down-disks }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "heketi-bootstrap.json.j2"
|
src: "heketi-bootstrap.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/heketi-bootstrap.json"
|
dest: "{{ kube_config_dir }}/heketi-bootstrap.json"
|
||||||
mode: "0640"
|
mode: 0640
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
- name: "Kubernetes Apps | Install and configure Heketi Bootstrap"
|
- name: "Kubernetes Apps | Install and configure Heketi Bootstrap"
|
||||||
kube:
|
kube:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "topology.json.j2"
|
src: "topology.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/topology.json"
|
dest: "{{ kube_config_dir }}/topology.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
- name: "Copy topology configuration into container."
|
- name: "Copy topology configuration into container."
|
||||||
changed_when: false
|
changed_when: false
|
||||||
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ initial_heketi_pod_name }}:/tmp/topology.json"
|
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ initial_heketi_pod_name }}:/tmp/topology.json"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "glusterfs-daemonset.json.j2"
|
src: "glusterfs-daemonset.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/glusterfs-daemonset.json"
|
dest: "{{ kube_config_dir }}/glusterfs-daemonset.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
become: true
|
become: true
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
- name: "Kubernetes Apps | Install and configure GlusterFS daemonset"
|
- name: "Kubernetes Apps | Install and configure GlusterFS daemonset"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "heketi-service-account.json.j2"
|
src: "heketi-service-account.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/heketi-service-account.json"
|
dest: "{{ kube_config_dir }}/heketi-service-account.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
become: true
|
become: true
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
- name: "Kubernetes Apps | Install and configure Heketi Service Account"
|
- name: "Kubernetes Apps | Install and configure Heketi Service Account"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "heketi-deployment.json.j2"
|
src: "heketi-deployment.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/heketi-deployment.json"
|
dest: "{{ kube_config_dir }}/heketi-deployment.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
|
|
||||||
- name: "Kubernetes Apps | Install and configure Heketi"
|
- name: "Kubernetes Apps | Install and configure Heketi"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "heketi.json.j2"
|
src: "heketi.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/heketi.json"
|
dest: "{{ kube_config_dir }}/heketi.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
|
|
||||||
- name: "Deploy Heketi config secret"
|
- name: "Deploy Heketi config secret"
|
||||||
when: "secret_state.stdout | length == 0"
|
when: "secret_state.stdout | length == 0"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "heketi-storage.json.j2"
|
src: "heketi-storage.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/heketi-storage.json"
|
dest: "{{ kube_config_dir }}/heketi-storage.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
- name: "Kubernetes Apps | Install and configure Heketi Storage"
|
- name: "Kubernetes Apps | Install and configure Heketi Storage"
|
||||||
kube:
|
kube:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "storageclass.yml.j2"
|
src: "storageclass.yml.j2"
|
||||||
dest: "{{ kube_config_dir }}/storageclass.yml"
|
dest: "{{ kube_config_dir }}/storageclass.yml"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
register: "rendering"
|
register: "rendering"
|
||||||
- name: "Kubernetes Apps | Install and configure Storace Class"
|
- name: "Kubernetes Apps | Install and configure Storace Class"
|
||||||
kube:
|
kube:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
template:
|
template:
|
||||||
src: "topology.json.j2"
|
src: "topology.json.j2"
|
||||||
dest: "{{ kube_config_dir }}/topology.json"
|
dest: "{{ kube_config_dir }}/topology.json"
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
- name: "Copy topology configuration into container." # noqa no-handler
|
- name: "Copy topology configuration into container." # noqa no-handler
|
||||||
when: "rendering.changed"
|
when: "rendering.changed"
|
||||||
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ heketi_pod_name }}:/tmp/topology.json"
|
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ heketi_pod_name }}:/tmp/topology.json"
|
||||||
|
|||||||
@@ -5,17 +5,13 @@
|
|||||||
Container image collecting script for offline deployment
|
Container image collecting script for offline deployment
|
||||||
|
|
||||||
This script has two features:
|
This script has two features:
|
||||||
(1) Get container images from an environment which is deployed online, or set IMAGES_FROM_FILE
|
(1) Get container images from an environment which is deployed online.
|
||||||
environment variable to get images from a file (e.g. temp/images.list after running the
|
|
||||||
./generate_list.sh script).
|
|
||||||
(2) Deploy local container registry and register the container images to the registry.
|
(2) Deploy local container registry and register the container images to the registry.
|
||||||
|
|
||||||
Step(1) should be done online site as a preparation, then we bring the gotten images
|
Step(1) should be done online site as a preparation, then we bring the gotten images
|
||||||
to the target offline environment. if images are from a private registry,
|
to the target offline environment. if images are from a private registry,
|
||||||
you need to set `PRIVATE_REGISTRY` environment variable.
|
you need to set `PRIVATE_REGISTRY` environment variable.
|
||||||
Then we will run step(2) for registering the images to local registry, or to an existing
|
Then we will run step(2) for registering the images to local registry.
|
||||||
registry set by the `DESTINATION_REGISTRY` environment variable. By default, the local registry
|
|
||||||
will run on port 5000. This can be changed with the `REGISTRY_PORT` environment variable
|
|
||||||
|
|
||||||
Step(1) can be operated with:
|
Step(1) can be operated with:
|
||||||
|
|
||||||
@@ -31,7 +27,7 @@ manage-offline-container-images.sh register
|
|||||||
|
|
||||||
## generate_list.sh
|
## generate_list.sh
|
||||||
|
|
||||||
This script generates the list of downloaded files and the list of container images by `roles/kubespray-defaults/defaults/main/download.yml` file.
|
This script generates the list of downloaded files and the list of container images by `roles/download/defaults/main/main.yml` file.
|
||||||
|
|
||||||
Run this script will execute `generate_list.yml` playbook in kubespray root directory and generate four files,
|
Run this script will execute `generate_list.yml` playbook in kubespray root directory and generate four files,
|
||||||
all downloaded files url in files.list, all container images in images.list, jinja2 templates in *.template.
|
all downloaded files url in files.list, all container images in images.list, jinja2 templates in *.template.
|
||||||
@@ -67,23 +63,3 @@ Step(2) download files and run nginx container
|
|||||||
```
|
```
|
||||||
|
|
||||||
when nginx container is running, it can be accessed through <http://127.0.0.1:8080/>.
|
when nginx container is running, it can be accessed through <http://127.0.0.1:8080/>.
|
||||||
|
|
||||||
## upload2artifactory.py
|
|
||||||
|
|
||||||
After the steps above, this script can recursively upload each file under a directory to a generic repository in Artifactory.
|
|
||||||
|
|
||||||
Environment Variables:
|
|
||||||
|
|
||||||
- USERNAME -- At least permissions'Deploy/Cache' and 'Delete/Overwrite'.
|
|
||||||
- TOKEN -- Generate this with 'Set Me Up' in your user.
|
|
||||||
- BASE_URL -- The URL including the repository name.
|
|
||||||
|
|
||||||
Step(3) (optional) upload files to Artifactory
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd kubespray/contrib/offline/offline-files
|
|
||||||
export USERNAME=admin
|
|
||||||
export TOKEN=...
|
|
||||||
export BASE_URL=https://artifactory.example.com/artifactory/a-generic-repo/
|
|
||||||
./upload2artifactory.py
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ CURRENT_DIR=$(cd $(dirname $0); pwd)
|
|||||||
TEMP_DIR="${CURRENT_DIR}/temp"
|
TEMP_DIR="${CURRENT_DIR}/temp"
|
||||||
REPO_ROOT_DIR="${CURRENT_DIR%/contrib/offline}"
|
REPO_ROOT_DIR="${CURRENT_DIR%/contrib/offline}"
|
||||||
|
|
||||||
: ${DOWNLOAD_YML:="roles/kubespray-defaults/defaults/main/download.yml"}
|
: ${DOWNLOAD_YML:="roles/download/defaults/main/main.yml"}
|
||||||
|
|
||||||
mkdir -p ${TEMP_DIR}
|
mkdir -p ${TEMP_DIR}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ sed -n '/^downloads:/,/download_defaults:/p' ${REPO_ROOT_DIR}/${DOWNLOAD_YML} \
|
|||||||
| sed 'N;s#\n# #g' | tr ' ' ':' | sed 's/\"//g' > ${TEMP_DIR}/images.list.template
|
| sed 'N;s#\n# #g' | tr ' ' ':' | sed 's/\"//g' > ${TEMP_DIR}/images.list.template
|
||||||
|
|
||||||
# add kube-* images to images list template
|
# add kube-* images to images list template
|
||||||
# Those container images are downloaded by kubeadm, then roles/kubespray-defaults/defaults/main/download.yml
|
# Those container images are downloaded by kubeadm, then roles/download/defaults/main/main.yml
|
||||||
# doesn't contain those images. That is reason why here needs to put those images into the
|
# doesn't contain those images. That is reason why here needs to put those images into the
|
||||||
# list separately.
|
# list separately.
|
||||||
KUBE_IMAGES="kube-apiserver kube-controller-manager kube-scheduler kube-proxy"
|
KUBE_IMAGES="kube-apiserver kube-controller-manager kube-scheduler kube-proxy"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: Collect container images for offline deployment
|
- name: Collect container images for offline deployment
|
||||||
hosts: localhost
|
hosts: localhost
|
||||||
become: false
|
become: no
|
||||||
|
|
||||||
roles:
|
roles:
|
||||||
# Just load default variables from roles.
|
# Just load default variables from roles.
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
template:
|
template:
|
||||||
src: ./contrib/offline/temp/{{ item }}.list.template
|
src: ./contrib/offline/temp/{{ item }}.list.template
|
||||||
dest: ./contrib/offline/temp/{{ item }}.list
|
dest: ./contrib/offline/temp/{{ item }}.list
|
||||||
mode: "0644"
|
mode: 0644
|
||||||
with_items:
|
with_items:
|
||||||
- files
|
- files
|
||||||
- images
|
- images
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
|
|
||||||
OPTION=$1
|
OPTION=$1
|
||||||
CURRENT_DIR=$(cd $(dirname $0); pwd)
|
CURRENT_DIR=$(cd $(dirname $0); pwd)
|
||||||
@@ -12,40 +12,27 @@ RETRY_COUNT=5
|
|||||||
function create_container_image_tar() {
|
function create_container_image_tar() {
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ -z "${IMAGES_FROM_FILE}" ]; then
|
IMAGES=$(kubectl describe pods --all-namespaces | grep " Image:" | awk '{print $2}' | sort | uniq)
|
||||||
echo "Getting images from current \"$(kubectl config current-context)\""
|
# NOTE: etcd and pause cannot be seen as pods.
|
||||||
|
# The pause image is used for --pod-infra-container-image option of kubelet.
|
||||||
IMAGES=$(mktemp --suffix=-images)
|
EXT_IMAGES=$(kubectl cluster-info dump | egrep "quay.io/coreos/etcd:|registry.k8s.io/pause:" | sed s@\"@@g)
|
||||||
trap 'rm -f "${IMAGES}"' EXIT
|
IMAGES="${IMAGES} ${EXT_IMAGES}"
|
||||||
|
|
||||||
kubectl describe cronjobs,jobs,pods --all-namespaces | grep " Image:" | awk '{print $2}' | sort | uniq > "${IMAGES}"
|
|
||||||
# NOTE: etcd and pause cannot be seen as pods.
|
|
||||||
# The pause image is used for --pod-infra-container-image option of kubelet.
|
|
||||||
kubectl cluster-info dump | grep -E "quay.io/coreos/etcd:|registry.k8s.io/pause:" | sed s@\"@@g >> "${IMAGES}"
|
|
||||||
else
|
|
||||||
echo "Getting images from file \"${IMAGES_FROM_FILE}\""
|
|
||||||
if [ ! -f "${IMAGES_FROM_FILE}" ]; then
|
|
||||||
echo "${IMAGES_FROM_FILE} is not a file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
IMAGES=$(realpath $IMAGES_FROM_FILE)
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f ${IMAGE_TAR_FILE}
|
rm -f ${IMAGE_TAR_FILE}
|
||||||
rm -rf ${IMAGE_DIR}
|
rm -rf ${IMAGE_DIR}
|
||||||
mkdir ${IMAGE_DIR}
|
mkdir ${IMAGE_DIR}
|
||||||
cd ${IMAGE_DIR}
|
cd ${IMAGE_DIR}
|
||||||
|
|
||||||
sudo ${runtime} pull registry:latest
|
sudo docker pull registry:latest
|
||||||
sudo ${runtime} save -o registry-latest.tar registry:latest
|
sudo docker save -o registry-latest.tar registry:latest
|
||||||
|
|
||||||
while read -r image
|
for image in ${IMAGES}
|
||||||
do
|
do
|
||||||
FILE_NAME="$(echo ${image} | sed s@"/"@"-"@g | sed s/":"/"-"/g | sed -E 's/\@.*//g')".tar
|
FILE_NAME="$(echo ${image} | sed s@"/"@"-"@g | sed s/":"/"-"/g)".tar
|
||||||
set +e
|
set +e
|
||||||
for step in $(seq 1 ${RETRY_COUNT})
|
for step in $(seq 1 ${RETRY_COUNT})
|
||||||
do
|
do
|
||||||
sudo ${runtime} pull ${image}
|
sudo docker pull ${image}
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -55,26 +42,24 @@ function create_container_image_tar() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
set -e
|
set -e
|
||||||
sudo ${runtime} save -o ${FILE_NAME} ${image}
|
sudo docker save -o ${FILE_NAME} ${image}
|
||||||
|
|
||||||
# NOTE: Here removes the following repo parts from each image
|
# NOTE: Here removes the following repo parts from each image
|
||||||
# so that these parts will be replaced with Kubespray.
|
# so that these parts will be replaced with Kubespray.
|
||||||
# - kube_image_repo: "registry.k8s.io"
|
# - kube_image_repo: "registry.k8s.io"
|
||||||
# - gcr_image_repo: "gcr.io"
|
# - gcr_image_repo: "gcr.io"
|
||||||
# - ghcr_image_repo: "ghcr.io"
|
|
||||||
# - docker_image_repo: "docker.io"
|
# - docker_image_repo: "docker.io"
|
||||||
# - quay_image_repo: "quay.io"
|
# - quay_image_repo: "quay.io"
|
||||||
FIRST_PART=$(echo ${image} | awk -F"/" '{print $1}')
|
FIRST_PART=$(echo ${image} | awk -F"/" '{print $1}')
|
||||||
if [ "${FIRST_PART}" = "registry.k8s.io" ] ||
|
if [ "${FIRST_PART}" = "registry.k8s.io" ] ||
|
||||||
[ "${FIRST_PART}" = "gcr.io" ] ||
|
[ "${FIRST_PART}" = "gcr.io" ] ||
|
||||||
[ "${FIRST_PART}" = "ghcr.io" ] ||
|
|
||||||
[ "${FIRST_PART}" = "docker.io" ] ||
|
[ "${FIRST_PART}" = "docker.io" ] ||
|
||||||
[ "${FIRST_PART}" = "quay.io" ] ||
|
[ "${FIRST_PART}" = "quay.io" ] ||
|
||||||
[ "${FIRST_PART}" = "${PRIVATE_REGISTRY}" ]; then
|
[ "${FIRST_PART}" = "${PRIVATE_REGISTRY}" ]; then
|
||||||
image=$(echo ${image} | sed s@"${FIRST_PART}/"@@ | sed -E 's/\@.*/\n/g')
|
image=$(echo ${image} | sed s@"${FIRST_PART}/"@@)
|
||||||
fi
|
fi
|
||||||
echo "${FILE_NAME} ${image}" >> ${IMAGE_LIST}
|
echo "${FILE_NAME} ${image}" >> ${IMAGE_LIST}
|
||||||
done < "${IMAGES}"
|
done
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sudo chown ${USER} ${IMAGE_DIR}/*
|
sudo chown ${USER} ${IMAGE_DIR}/*
|
||||||
@@ -87,16 +72,6 @@ function create_container_image_tar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function register_container_images() {
|
function register_container_images() {
|
||||||
create_registry=false
|
|
||||||
REGISTRY_PORT=${REGISTRY_PORT:-"5000"}
|
|
||||||
|
|
||||||
if [ -z "${DESTINATION_REGISTRY}" ]; then
|
|
||||||
echo "DESTINATION_REGISTRY not set, will create local registry"
|
|
||||||
create_registry=true
|
|
||||||
DESTINATION_REGISTRY="$(hostname):${REGISTRY_PORT}"
|
|
||||||
fi
|
|
||||||
echo "Images will be pushed to ${DESTINATION_REGISTRY}"
|
|
||||||
|
|
||||||
if [ ! -f ${IMAGE_TAR_FILE} ]; then
|
if [ ! -f ${IMAGE_TAR_FILE} ]; then
|
||||||
echo "${IMAGE_TAR_FILE} should exist."
|
echo "${IMAGE_TAR_FILE} should exist."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -106,49 +81,39 @@ function register_container_images() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# To avoid "http: server gave http response to https client" error.
|
# To avoid "http: server gave http response to https client" error.
|
||||||
|
LOCALHOST_NAME=$(hostname)
|
||||||
if [ -d /etc/docker/ ]; then
|
if [ -d /etc/docker/ ]; then
|
||||||
set -e
|
set -e
|
||||||
# Ubuntu18.04, RHEL7/CentOS7
|
# Ubuntu18.04, RHEL7/CentOS7
|
||||||
cp ${CURRENT_DIR}/docker-daemon.json ${TEMP_DIR}/docker-daemon.json
|
cp ${CURRENT_DIR}/docker-daemon.json ${TEMP_DIR}/docker-daemon.json
|
||||||
sed -i s@"HOSTNAME"@"$(hostname)"@ ${TEMP_DIR}/docker-daemon.json
|
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/docker-daemon.json
|
||||||
sudo cp ${TEMP_DIR}/docker-daemon.json /etc/docker/daemon.json
|
sudo cp ${TEMP_DIR}/docker-daemon.json /etc/docker/daemon.json
|
||||||
elif [ -d /etc/containers/ ]; then
|
elif [ -d /etc/containers/ ]; then
|
||||||
set -e
|
set -e
|
||||||
# RHEL8/CentOS8
|
# RHEL8/CentOS8
|
||||||
cp ${CURRENT_DIR}/registries.conf ${TEMP_DIR}/registries.conf
|
cp ${CURRENT_DIR}/registries.conf ${TEMP_DIR}/registries.conf
|
||||||
sed -i s@"HOSTNAME"@"$(hostname)"@ ${TEMP_DIR}/registries.conf
|
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/registries.conf
|
||||||
sudo cp ${TEMP_DIR}/registries.conf /etc/containers/registries.conf
|
sudo cp ${TEMP_DIR}/registries.conf /etc/containers/registries.conf
|
||||||
elif [ "$(uname)" == "Darwin" ]; then
|
|
||||||
echo "This is a Mac, no configuration changes are required"
|
|
||||||
else
|
else
|
||||||
echo "runtime package(docker-ce, podman, nerctl, etc.) should be installed"
|
echo "docker package(docker-ce, etc.) should be installed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tar -zxvf ${IMAGE_TAR_FILE}
|
tar -zxvf ${IMAGE_TAR_FILE}
|
||||||
|
sudo docker load -i ${IMAGE_DIR}/registry-latest.tar
|
||||||
if [ "${create_registry}" ]; then
|
set +e
|
||||||
sudo ${runtime} load -i ${IMAGE_DIR}/registry-latest.tar
|
sudo docker container inspect registry >/dev/null 2>&1
|
||||||
set +e
|
if [ $? -ne 0 ]; then
|
||||||
|
sudo docker run --restart=always -d -p 5000:5000 --name registry registry:latest
|
||||||
sudo ${runtime} container inspect registry >/dev/null 2>&1
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
sudo ${runtime} run --restart=always -d -p "${REGISTRY_PORT}":"${REGISTRY_PORT}" --name registry registry:latest
|
|
||||||
fi
|
|
||||||
set -e
|
|
||||||
fi
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
file_name=$(echo ${line} | awk '{print $1}')
|
file_name=$(echo ${line} | awk '{print $1}')
|
||||||
raw_image=$(echo ${line} | awk '{print $2}')
|
raw_image=$(echo ${line} | awk '{print $2}')
|
||||||
new_image="${DESTINATION_REGISTRY}/${raw_image}"
|
new_image="${LOCALHOST_NAME}:5000/${raw_image}"
|
||||||
load_image=$(sudo ${runtime} load -i ${IMAGE_DIR}/${file_name} | head -n1)
|
org_image=$(sudo docker load -i ${IMAGE_DIR}/${file_name} | head -n1 | awk '{print $3}')
|
||||||
org_image=$(echo "${load_image}" | awk '{print $3}')
|
image_id=$(sudo docker image inspect ${org_image} | grep "\"Id\":" | awk -F: '{print $3}'| sed s/'\",'//)
|
||||||
# special case for tags containing the digest when using docker or podman as the container runtime
|
|
||||||
if [ "${org_image}" == "ID:" ]; then
|
|
||||||
org_image=$(echo "${load_image}" | awk '{print $4}')
|
|
||||||
fi
|
|
||||||
image_id=$(sudo ${runtime} image inspect ${org_image} | grep "\"Id\":" | awk -F: '{print $3}'| sed s/'\",'//)
|
|
||||||
if [ -z "${file_name}" ]; then
|
if [ -z "${file_name}" ]; then
|
||||||
echo "Failed to get file_name for line ${line}"
|
echo "Failed to get file_name for line ${line}"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -165,48 +130,32 @@ function register_container_images() {
|
|||||||
echo "Failed to get image_id for file ${file_name}"
|
echo "Failed to get image_id for file ${file_name}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
sudo ${runtime} load -i ${IMAGE_DIR}/${file_name}
|
sudo docker load -i ${IMAGE_DIR}/${file_name}
|
||||||
sudo ${runtime} tag ${image_id} ${new_image}
|
sudo docker tag ${image_id} ${new_image}
|
||||||
sudo ${runtime} push ${new_image}
|
sudo docker push ${new_image}
|
||||||
done <<< "$(cat ${IMAGE_LIST})"
|
done <<< "$(cat ${IMAGE_LIST})"
|
||||||
|
|
||||||
echo "Succeeded to register container images to local registry."
|
echo "Succeeded to register container images to local registry."
|
||||||
echo "Please specify \"${DESTINATION_REGISTRY}\" for the following options in your inventry:"
|
echo "Please specify ${LOCALHOST_NAME}:5000 for the following options in your inventry:"
|
||||||
echo "- kube_image_repo"
|
echo "- kube_image_repo"
|
||||||
echo "- gcr_image_repo"
|
echo "- gcr_image_repo"
|
||||||
echo "- docker_image_repo"
|
echo "- docker_image_repo"
|
||||||
echo "- quay_image_repo"
|
echo "- quay_image_repo"
|
||||||
}
|
}
|
||||||
|
|
||||||
# get runtime command
|
|
||||||
if command -v nerdctl 1>/dev/null 2>&1; then
|
|
||||||
runtime="nerdctl"
|
|
||||||
elif command -v podman 1>/dev/null 2>&1; then
|
|
||||||
runtime="podman"
|
|
||||||
elif command -v docker 1>/dev/null 2>&1; then
|
|
||||||
runtime="docker"
|
|
||||||
else
|
|
||||||
echo "No supported container runtime found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${OPTION}" == "create" ]; then
|
if [ "${OPTION}" == "create" ]; then
|
||||||
create_container_image_tar
|
create_container_image_tar
|
||||||
elif [ "${OPTION}" == "register" ]; then
|
elif [ "${OPTION}" == "register" ]; then
|
||||||
register_container_images
|
register_container_images
|
||||||
else
|
else
|
||||||
echo "This script has two features:"
|
echo "This script has two features:"
|
||||||
echo "(1) Get container images from an environment which is deployed online, or set IMAGES_FROM_FILE"
|
echo "(1) Get container images from an environment which is deployed online."
|
||||||
echo " environment variable to get images from a file (e.g. temp/images.list after running the"
|
|
||||||
echo " ./generate_list.sh script)."
|
|
||||||
echo "(2) Deploy local container registry and register the container images to the registry."
|
echo "(2) Deploy local container registry and register the container images to the registry."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Step(1) should be done online site as a preparation, then we bring"
|
echo "Step(1) should be done online site as a preparation, then we bring"
|
||||||
echo "the gotten images to the target offline environment. if images are from"
|
echo "the gotten images to the target offline environment. if images are from"
|
||||||
echo "a private registry, you need to set PRIVATE_REGISTRY environment variable."
|
echo "a private registry, you need to set PRIVATE_REGISTRY environment variable."
|
||||||
echo "Then we will run step(2) for registering the images to local registry, or to an existing"
|
echo "Then we will run step(2) for registering the images to local registry."
|
||||||
echo "registry set by the DESTINATION_REGISTRY environment variable. By default, the local registry"
|
|
||||||
echo "will run on port 5000. This can be changed with the REGISTRY_PORT environment variable"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "${IMAGE_TAR_FILE} is created to contain your container images."
|
echo "${IMAGE_TAR_FILE} is created to contain your container images."
|
||||||
echo "Please keep this file and bring it to your offline environment."
|
echo "Please keep this file and bring it to your offline environment."
|
||||||
|
|||||||
@@ -17,12 +17,7 @@ rm -rf "${OFFLINE_FILES_DIR}"
|
|||||||
rm "${OFFLINE_FILES_ARCHIVE}"
|
rm "${OFFLINE_FILES_ARCHIVE}"
|
||||||
mkdir "${OFFLINE_FILES_DIR}"
|
mkdir "${OFFLINE_FILES_DIR}"
|
||||||
|
|
||||||
while read -r url; do
|
wget -x -P "${OFFLINE_FILES_DIR}" -i "${FILES_LIST}"
|
||||||
if ! wget -x -P "${OFFLINE_FILES_DIR}" "${url}"; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done < "${FILES_LIST}"
|
|
||||||
|
|
||||||
tar -czvf "${OFFLINE_FILES_ARCHIVE}" "${OFFLINE_FILES_DIR_NAME}"
|
tar -czvf "${OFFLINE_FILES_ARCHIVE}" "${OFFLINE_FILES_DIR_NAME}"
|
||||||
|
|
||||||
[ -n "$NO_HTTP_SERVER" ] && echo "skip to run nginx" && exit 0
|
[ -n "$NO_HTTP_SERVER" ] && echo "skip to run nginx" && exit 0
|
||||||
@@ -43,7 +38,7 @@ sudo "${runtime}" container inspect nginx >/dev/null 2>&1
|
|||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
sudo "${runtime}" run \
|
sudo "${runtime}" run \
|
||||||
--restart=always -d -p ${NGINX_PORT}:80 \
|
--restart=always -d -p ${NGINX_PORT}:80 \
|
||||||
--volume "${OFFLINE_FILES_DIR}":/usr/share/nginx/html/download \
|
--volume "${OFFLINE_FILES_DIR}:/usr/share/nginx/html/download" \
|
||||||
--volume "${CURRENT_DIR}"/nginx.conf:/etc/nginx/nginx.conf \
|
--volume "${CURRENT_DIR}"/nginx.conf:/etc/nginx/nginx.conf \
|
||||||
--name nginx nginx:alpine
|
--name nginx nginx:alpine
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""This is a helper script to manage-offline-files.sh.
|
|
||||||
|
|
||||||
After running manage-offline-files.sh, you can run upload2artifactory.py
|
|
||||||
to recursively upload each file to a generic repository in Artifactory.
|
|
||||||
|
|
||||||
This script recurses the current working directory and is intended to
|
|
||||||
be started from 'kubespray/contrib/offline/offline-files'
|
|
||||||
|
|
||||||
Environment Variables:
|
|
||||||
USERNAME -- At least permissions'Deploy/Cache' and 'Delete/Overwrite'.
|
|
||||||
TOKEN -- Generate this with 'Set Me Up' in your user.
|
|
||||||
BASE_URL -- The URL including the repository name.
|
|
||||||
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import urllib.request
|
|
||||||
import base64
|
|
||||||
|
|
||||||
|
|
||||||
def upload_file(file_path, destination_url, username, token):
|
|
||||||
"""Helper function to upload a single file"""
|
|
||||||
try:
|
|
||||||
with open(file_path, 'rb') as f:
|
|
||||||
file_data = f.read()
|
|
||||||
|
|
||||||
request = urllib.request.Request(destination_url, data=file_data, method='PUT') # NOQA
|
|
||||||
auth_header = base64.b64encode(f"{username}:{token}".encode()).decode()
|
|
||||||
request.add_header("Authorization", f"Basic {auth_header}")
|
|
||||||
|
|
||||||
with urllib.request.urlopen(request) as response:
|
|
||||||
if response.status in [200, 201]:
|
|
||||||
print(f"Success: Uploaded {file_path}")
|
|
||||||
else:
|
|
||||||
print(f"Failed: {response.status} {response.read().decode('utf-8')}") # NOQA
|
|
||||||
except urllib.error.HTTPError as e:
|
|
||||||
print(f"HTTPError: {e.code} {e.reason} for {file_path}")
|
|
||||||
except urllib.error.URLError as e:
|
|
||||||
print(f"URLError: {e.reason} for {file_path}")
|
|
||||||
except OSError as e:
|
|
||||||
print(f"OSError: {e.strerror} for {file_path}")
|
|
||||||
|
|
||||||
|
|
||||||
def upload_files(base_url, username, token):
|
|
||||||
""" Recurse current dir and upload each file using urllib.request """
|
|
||||||
for root, _, files in os.walk(os.getcwd()):
|
|
||||||
for file in files:
|
|
||||||
file_path = os.path.join(root, file)
|
|
||||||
relative_path = os.path.relpath(file_path, os.getcwd())
|
|
||||||
destination_url = f"{base_url}/{relative_path}"
|
|
||||||
|
|
||||||
print(f"Uploading {file_path} to {destination_url}")
|
|
||||||
upload_file(file_path, destination_url, username, token)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
a_user = os.getenv("USERNAME")
|
|
||||||
a_token = os.getenv("TOKEN")
|
|
||||||
a_url = os.getenv("BASE_URL")
|
|
||||||
if not a_user or not a_token or not a_url:
|
|
||||||
print(
|
|
||||||
"Error: Environment variables USERNAME, TOKEN, and BASE_URL must be set." # NOQA
|
|
||||||
)
|
|
||||||
exit()
|
|
||||||
upload_files(a_url, a_user, a_token)
|
|
||||||
@@ -7,17 +7,17 @@
|
|||||||
service_facts:
|
service_facts:
|
||||||
|
|
||||||
- name: Disable service firewalld
|
- name: Disable service firewalld
|
||||||
systemd_service:
|
systemd:
|
||||||
name: firewalld
|
name: firewalld
|
||||||
state: stopped
|
state: stopped
|
||||||
enabled: false
|
enabled: no
|
||||||
when:
|
when:
|
||||||
"'firewalld.service' in services and services['firewalld.service'].status != 'not-found'"
|
"'firewalld.service' in services and services['firewalld.service'].status != 'not-found'"
|
||||||
|
|
||||||
- name: Disable service ufw
|
- name: Disable service ufw
|
||||||
systemd_service:
|
systemd:
|
||||||
name: ufw
|
name: ufw
|
||||||
state: stopped
|
state: stopped
|
||||||
enabled: false
|
enabled: no
|
||||||
when:
|
when:
|
||||||
"'ufw.service' in services and services['ufw.service'].status != 'not-found'"
|
"'ufw.service' in services and services['ufw.service'].status != 'not-found'"
|
||||||
|
|||||||
62
contrib/packaging/rpm/kubespray.spec
Normal file
62
contrib/packaging/rpm/kubespray.spec
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
%global srcname kubespray
|
||||||
|
|
||||||
|
%{!?upstream_version: %global upstream_version %{version}%{?milestone}}
|
||||||
|
|
||||||
|
Name: kubespray
|
||||||
|
Version: master
|
||||||
|
Release: %(git describe | sed -r 's/v(\S+-?)-(\S+)-(\S+)/\1.dev\2+\3/')
|
||||||
|
Summary: Ansible modules for installing Kubernetes
|
||||||
|
|
||||||
|
Group: System Environment/Libraries
|
||||||
|
License: ASL 2.0
|
||||||
|
Url: https://github.com/kubernetes-sigs/kubespray
|
||||||
|
Source0: https://github.com/kubernetes-sigs/kubespray/archive/%{upstream_version}.tar.gz#/%{name}-%{release}.tar.gz
|
||||||
|
|
||||||
|
BuildArch: noarch
|
||||||
|
BuildRequires: git
|
||||||
|
BuildRequires: python2
|
||||||
|
BuildRequires: python2-devel
|
||||||
|
BuildRequires: python2-setuptools
|
||||||
|
BuildRequires: python-d2to1
|
||||||
|
BuildRequires: python2-pbr
|
||||||
|
|
||||||
|
Requires: ansible >= 2.5.0
|
||||||
|
Requires: python-jinja2 >= 2.10
|
||||||
|
Requires: python-netaddr
|
||||||
|
Requires: python-pbr
|
||||||
|
|
||||||
|
%description
|
||||||
|
|
||||||
|
Ansible-kubespray is a set of Ansible modules and playbooks for
|
||||||
|
installing a Kubernetes cluster. If you have questions, join us
|
||||||
|
on the https://slack.k8s.io, channel '#kubespray'.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n %{name}-%{upstream_version} -S git
|
||||||
|
|
||||||
|
|
||||||
|
%build
|
||||||
|
export PBR_VERSION=%{release}
|
||||||
|
%{__python2} setup.py build bdist_rpm
|
||||||
|
|
||||||
|
|
||||||
|
%install
|
||||||
|
export PBR_VERSION=%{release}
|
||||||
|
export SKIP_PIP_INSTALL=1
|
||||||
|
%{__python2} setup.py install --skip-build --root %{buildroot} bdist_rpm
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc %{_docdir}/%{name}/README.md
|
||||||
|
%doc %{_docdir}/%{name}/inventory/sample/hosts.ini
|
||||||
|
%config %{_sysconfdir}/%{name}/ansible.cfg
|
||||||
|
%config %{_sysconfdir}/%{name}/inventory/sample/group_vars/all.yml
|
||||||
|
%config %{_sysconfdir}/%{name}/inventory/sample/group_vars/k8s_cluster.yml
|
||||||
|
%license %{_docdir}/%{name}/LICENSE
|
||||||
|
%{python2_sitelib}/%{srcname}-%{release}-py%{python2_version}.egg-info
|
||||||
|
%{_datarootdir}/%{name}/roles/
|
||||||
|
%{_datarootdir}/%{name}/playbooks/
|
||||||
|
%defattr(-,root,root)
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
5
contrib/terraform/OWNERS
Normal file
5
contrib/terraform/OWNERS
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# See the OWNERS docs at https://go.k8s.io/owners
|
||||||
|
|
||||||
|
approvers:
|
||||||
|
- holmsten
|
||||||
|
- miouge1
|
||||||
@@ -50,32 +50,70 @@ Example (this one assumes you are using Ubuntu)
|
|||||||
ansible-playbook -i ./inventory/hosts ./cluster.yml -e ansible_user=ubuntu -b --become-user=root --flush-cache
|
ansible-playbook -i ./inventory/hosts ./cluster.yml -e ansible_user=ubuntu -b --become-user=root --flush-cache
|
||||||
```
|
```
|
||||||
|
|
||||||
## Using other distrib than Ubuntu***
|
***Using other distrib than Ubuntu***
|
||||||
|
If you want to use another distribution than Ubuntu 18.04 (Bionic) LTS, you can modify the search filters of the 'data "aws_ami" "distro"' in variables.tf.
|
||||||
|
|
||||||
To leverage a Linux distribution other than Ubuntu 18.04 (Bionic) LTS for your Terraform configurations, you can adjust the AMI search filters within the 'data "aws_ami" "distro"' block by utilizing variables in your `terraform.tfvars` file. This approach ensures a flexible configuration that adapts to various Linux distributions without directly modifying the core Terraform files.
|
For example, to use:
|
||||||
|
|
||||||
### Example Usages
|
- Debian Jessie, replace 'data "aws_ami" "distro"' in variables.tf with
|
||||||
|
|
||||||
- **Debian Jessie**: To configure the usage of Debian Jessie, insert the subsequent lines into your `terraform.tfvars`:
|
```ini
|
||||||
|
data "aws_ami" "distro" {
|
||||||
|
most_recent = true
|
||||||
|
|
||||||
```hcl
|
filter {
|
||||||
ami_name_pattern = "debian-jessie-amd64-hvm-*"
|
name = "name"
|
||||||
ami_owners = ["379101102735"]
|
values = ["debian-jessie-amd64-hvm-*"]
|
||||||
```
|
}
|
||||||
|
|
||||||
- **Ubuntu 16.04**: To utilize Ubuntu 16.04 instead, apply the following configuration in your `terraform.tfvars`:
|
filter {
|
||||||
|
name = "virtualization-type"
|
||||||
|
values = ["hvm"]
|
||||||
|
}
|
||||||
|
|
||||||
```hcl
|
owners = ["379101102735"]
|
||||||
ami_name_pattern = "ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-*"
|
}
|
||||||
ami_owners = ["099720109477"]
|
```
|
||||||
```
|
|
||||||
|
|
||||||
- **Centos 7**: For employing Centos 7, incorporate these lines into your `terraform.tfvars`:
|
- Ubuntu 16.04, replace 'data "aws_ami" "distro"' in variables.tf with
|
||||||
|
|
||||||
```hcl
|
```ini
|
||||||
ami_name_pattern = "dcos-centos7-*"
|
data "aws_ami" "distro" {
|
||||||
ami_owners = ["688023202711"]
|
most_recent = true
|
||||||
```
|
|
||||||
|
filter {
|
||||||
|
name = "name"
|
||||||
|
values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
filter {
|
||||||
|
name = "virtualization-type"
|
||||||
|
values = ["hvm"]
|
||||||
|
}
|
||||||
|
|
||||||
|
owners = ["099720109477"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Centos 7, replace 'data "aws_ami" "distro"' in variables.tf with
|
||||||
|
|
||||||
|
```ini
|
||||||
|
data "aws_ami" "distro" {
|
||||||
|
most_recent = true
|
||||||
|
|
||||||
|
filter {
|
||||||
|
name = "name"
|
||||||
|
values = ["dcos-centos7-*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
filter {
|
||||||
|
name = "virtualization-type"
|
||||||
|
values = ["hvm"]
|
||||||
|
}
|
||||||
|
|
||||||
|
owners = ["688023202711"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Connecting to Kubernetes
|
## Connecting to Kubernetes
|
||||||
|
|
||||||
|
|||||||
@@ -20,38 +20,20 @@ variable "aws_cluster_name" {
|
|||||||
description = "Name of AWS Cluster"
|
description = "Name of AWS Cluster"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "ami_name_pattern" {
|
|
||||||
description = "The name pattern to use for AMI lookup"
|
|
||||||
type = string
|
|
||||||
default = "debian-10-amd64-*"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "ami_virtualization_type" {
|
|
||||||
description = "The virtualization type to use for AMI lookup"
|
|
||||||
type = string
|
|
||||||
default = "hvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "ami_owners" {
|
|
||||||
description = "The owners to use for AMI lookup"
|
|
||||||
type = list(string)
|
|
||||||
default = ["136693071363"]
|
|
||||||
}
|
|
||||||
|
|
||||||
data "aws_ami" "distro" {
|
data "aws_ami" "distro" {
|
||||||
most_recent = true
|
most_recent = true
|
||||||
|
|
||||||
filter {
|
filter {
|
||||||
name = "name"
|
name = "name"
|
||||||
values = [var.ami_name_pattern]
|
values = ["debian-10-amd64-*"]
|
||||||
}
|
}
|
||||||
|
|
||||||
filter {
|
filter {
|
||||||
name = "virtualization-type"
|
name = "virtualization-type"
|
||||||
values = [var.ami_virtualization_type]
|
values = ["hvm"]
|
||||||
}
|
}
|
||||||
|
|
||||||
owners = var.ami_owners
|
owners = ["136693071363"] # Debian-10
|
||||||
}
|
}
|
||||||
|
|
||||||
//AWS VPC Variables
|
//AWS VPC Variables
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ now six total etcd replicas.
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- [Install Terraform](https://www.terraform.io/intro/getting-started/install.html)
|
- [Install Terraform](https://www.terraform.io/intro/getting-started/install.html)
|
||||||
- [Install Ansible dependencies](/docs/ansible/ansible.md#installing-ansible)
|
- [Install Ansible dependencies](/docs/ansible.md#installing-ansible)
|
||||||
- Account with Equinix Metal
|
- Account with Equinix Metal
|
||||||
- An SSH key pair
|
- An SSH key pair
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
equinix = {
|
equinix = {
|
||||||
source = "equinix/equinix"
|
source = "equinix/equinix"
|
||||||
version = "1.24.0"
|
version = "~> 1.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ ssh_public_keys = [
|
|||||||
machines = {
|
machines = {
|
||||||
"master-0" : {
|
"master-0" : {
|
||||||
"node_type" : "master",
|
"node_type" : "master",
|
||||||
"size" : "standard.medium",
|
"size" : "Medium",
|
||||||
"boot_disk" : {
|
"boot_disk" : {
|
||||||
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
||||||
"root_partition_size" : 50,
|
"root_partition_size" : 50,
|
||||||
@@ -22,7 +22,7 @@ machines = {
|
|||||||
},
|
},
|
||||||
"worker-0" : {
|
"worker-0" : {
|
||||||
"node_type" : "worker",
|
"node_type" : "worker",
|
||||||
"size" : "standard.large",
|
"size" : "Large",
|
||||||
"boot_disk" : {
|
"boot_disk" : {
|
||||||
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
||||||
"root_partition_size" : 50,
|
"root_partition_size" : 50,
|
||||||
@@ -32,7 +32,7 @@ machines = {
|
|||||||
},
|
},
|
||||||
"worker-1" : {
|
"worker-1" : {
|
||||||
"node_type" : "worker",
|
"node_type" : "worker",
|
||||||
"size" : "standard.large",
|
"size" : "Large",
|
||||||
"boot_disk" : {
|
"boot_disk" : {
|
||||||
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
||||||
"root_partition_size" : 50,
|
"root_partition_size" : 50,
|
||||||
@@ -42,7 +42,7 @@ machines = {
|
|||||||
},
|
},
|
||||||
"worker-2" : {
|
"worker-2" : {
|
||||||
"node_type" : "worker",
|
"node_type" : "worker",
|
||||||
"size" : "standard.large",
|
"size" : "Large",
|
||||||
"boot_disk" : {
|
"boot_disk" : {
|
||||||
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
"image_name" : "Linux Ubuntu 20.04 LTS 64-bit",
|
||||||
"root_partition_size" : 50,
|
"root_partition_size" : 50,
|
||||||
|
|||||||
@@ -1,25 +1,29 @@
|
|||||||
data "exoscale_template" "os_image" {
|
data "exoscale_compute_template" "os_image" {
|
||||||
for_each = var.machines
|
for_each = var.machines
|
||||||
|
|
||||||
zone = var.zone
|
zone = var.zone
|
||||||
name = each.value.boot_disk.image_name
|
name = each.value.boot_disk.image_name
|
||||||
}
|
}
|
||||||
|
|
||||||
data "exoscale_compute_instance" "master_nodes" {
|
data "exoscale_compute" "master_nodes" {
|
||||||
for_each = exoscale_compute_instance.master
|
for_each = exoscale_compute.master
|
||||||
|
|
||||||
id = each.value.id
|
id = each.value.id
|
||||||
zone = var.zone
|
|
||||||
|
# Since private IP address is not assigned until the nics are created we need this
|
||||||
|
depends_on = [exoscale_nic.master_private_network_nic]
|
||||||
}
|
}
|
||||||
|
|
||||||
data "exoscale_compute_instance" "worker_nodes" {
|
data "exoscale_compute" "worker_nodes" {
|
||||||
for_each = exoscale_compute_instance.worker
|
for_each = exoscale_compute.worker
|
||||||
|
|
||||||
id = each.value.id
|
id = each.value.id
|
||||||
zone = var.zone
|
|
||||||
|
# Since private IP address is not assigned until the nics are created we need this
|
||||||
|
depends_on = [exoscale_nic.worker_private_network_nic]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_private_network" "private_network" {
|
resource "exoscale_network" "private_network" {
|
||||||
zone = var.zone
|
zone = var.zone
|
||||||
name = "${var.prefix}-network"
|
name = "${var.prefix}-network"
|
||||||
|
|
||||||
@@ -30,29 +34,25 @@ resource "exoscale_private_network" "private_network" {
|
|||||||
netmask = cidrnetmask(var.private_network_cidr)
|
netmask = cidrnetmask(var.private_network_cidr)
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_compute_instance" "master" {
|
resource "exoscale_compute" "master" {
|
||||||
for_each = {
|
for_each = {
|
||||||
for name, machine in var.machines :
|
for name, machine in var.machines :
|
||||||
name => machine
|
name => machine
|
||||||
if machine.node_type == "master"
|
if machine.node_type == "master"
|
||||||
}
|
}
|
||||||
|
|
||||||
name = "${var.prefix}-${each.key}"
|
display_name = "${var.prefix}-${each.key}"
|
||||||
template_id = data.exoscale_template.os_image[each.key].id
|
template_id = data.exoscale_compute_template.os_image[each.key].id
|
||||||
type = each.value.size
|
size = each.value.size
|
||||||
disk_size = each.value.boot_disk.root_partition_size + each.value.boot_disk.node_local_partition_size + each.value.boot_disk.ceph_partition_size
|
disk_size = each.value.boot_disk.root_partition_size + each.value.boot_disk.node_local_partition_size + each.value.boot_disk.ceph_partition_size
|
||||||
state = "Running"
|
state = "Running"
|
||||||
zone = var.zone
|
zone = var.zone
|
||||||
security_group_ids = [exoscale_security_group.master_sg.id]
|
security_groups = [exoscale_security_group.master_sg.name]
|
||||||
network_interface {
|
|
||||||
network_id = exoscale_private_network.private_network.id
|
|
||||||
}
|
|
||||||
elastic_ip_ids = [exoscale_elastic_ip.control_plane_lb.id]
|
|
||||||
|
|
||||||
user_data = templatefile(
|
user_data = templatefile(
|
||||||
"${path.module}/templates/cloud-init.tmpl",
|
"${path.module}/templates/cloud-init.tmpl",
|
||||||
{
|
{
|
||||||
eip_ip_address = exoscale_elastic_ip.ingress_controller_lb.ip_address
|
eip_ip_address = exoscale_ipaddress.ingress_controller_lb.ip_address
|
||||||
node_local_partition_size = each.value.boot_disk.node_local_partition_size
|
node_local_partition_size = each.value.boot_disk.node_local_partition_size
|
||||||
ceph_partition_size = each.value.boot_disk.ceph_partition_size
|
ceph_partition_size = each.value.boot_disk.ceph_partition_size
|
||||||
root_partition_size = each.value.boot_disk.root_partition_size
|
root_partition_size = each.value.boot_disk.root_partition_size
|
||||||
@@ -62,29 +62,25 @@ resource "exoscale_compute_instance" "master" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_compute_instance" "worker" {
|
resource "exoscale_compute" "worker" {
|
||||||
for_each = {
|
for_each = {
|
||||||
for name, machine in var.machines :
|
for name, machine in var.machines :
|
||||||
name => machine
|
name => machine
|
||||||
if machine.node_type == "worker"
|
if machine.node_type == "worker"
|
||||||
}
|
}
|
||||||
|
|
||||||
name = "${var.prefix}-${each.key}"
|
display_name = "${var.prefix}-${each.key}"
|
||||||
template_id = data.exoscale_template.os_image[each.key].id
|
template_id = data.exoscale_compute_template.os_image[each.key].id
|
||||||
type = each.value.size
|
size = each.value.size
|
||||||
disk_size = each.value.boot_disk.root_partition_size + each.value.boot_disk.node_local_partition_size + each.value.boot_disk.ceph_partition_size
|
disk_size = each.value.boot_disk.root_partition_size + each.value.boot_disk.node_local_partition_size + each.value.boot_disk.ceph_partition_size
|
||||||
state = "Running"
|
state = "Running"
|
||||||
zone = var.zone
|
zone = var.zone
|
||||||
security_group_ids = [exoscale_security_group.worker_sg.id]
|
security_groups = [exoscale_security_group.worker_sg.name]
|
||||||
network_interface {
|
|
||||||
network_id = exoscale_private_network.private_network.id
|
|
||||||
}
|
|
||||||
elastic_ip_ids = [exoscale_elastic_ip.ingress_controller_lb.id]
|
|
||||||
|
|
||||||
user_data = templatefile(
|
user_data = templatefile(
|
||||||
"${path.module}/templates/cloud-init.tmpl",
|
"${path.module}/templates/cloud-init.tmpl",
|
||||||
{
|
{
|
||||||
eip_ip_address = exoscale_elastic_ip.ingress_controller_lb.ip_address
|
eip_ip_address = exoscale_ipaddress.ingress_controller_lb.ip_address
|
||||||
node_local_partition_size = each.value.boot_disk.node_local_partition_size
|
node_local_partition_size = each.value.boot_disk.node_local_partition_size
|
||||||
ceph_partition_size = each.value.boot_disk.ceph_partition_size
|
ceph_partition_size = each.value.boot_disk.ceph_partition_size
|
||||||
root_partition_size = each.value.boot_disk.root_partition_size
|
root_partition_size = each.value.boot_disk.root_partition_size
|
||||||
@@ -94,33 +90,41 @@ resource "exoscale_compute_instance" "worker" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "exoscale_nic" "master_private_network_nic" {
|
||||||
|
for_each = exoscale_compute.master
|
||||||
|
|
||||||
|
compute_id = each.value.id
|
||||||
|
network_id = exoscale_network.private_network.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "exoscale_nic" "worker_private_network_nic" {
|
||||||
|
for_each = exoscale_compute.worker
|
||||||
|
|
||||||
|
compute_id = each.value.id
|
||||||
|
network_id = exoscale_network.private_network.id
|
||||||
|
}
|
||||||
|
|
||||||
resource "exoscale_security_group" "master_sg" {
|
resource "exoscale_security_group" "master_sg" {
|
||||||
name = "${var.prefix}-master-sg"
|
name = "${var.prefix}-master-sg"
|
||||||
description = "Security group for Kubernetes masters"
|
description = "Security group for Kubernetes masters"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_security_group_rule" "master_sg_rule_ssh" {
|
resource "exoscale_security_group_rules" "master_sg_rules" {
|
||||||
security_group_id = exoscale_security_group.master_sg.id
|
security_group_id = exoscale_security_group.master_sg.id
|
||||||
|
|
||||||
for_each = toset(var.ssh_whitelist)
|
|
||||||
# SSH
|
# SSH
|
||||||
type = "INGRESS"
|
ingress {
|
||||||
start_port = 22
|
protocol = "TCP"
|
||||||
end_port = 22
|
cidr_list = var.ssh_whitelist
|
||||||
protocol = "TCP"
|
ports = ["22"]
|
||||||
cidr = each.value
|
}
|
||||||
}
|
|
||||||
|
|
||||||
resource "exoscale_security_group_rule" "master_sg_rule_k8s_api" {
|
|
||||||
security_group_id = exoscale_security_group.master_sg.id
|
|
||||||
|
|
||||||
for_each = toset(var.api_server_whitelist)
|
|
||||||
# Kubernetes API
|
# Kubernetes API
|
||||||
type = "INGRESS"
|
ingress {
|
||||||
start_port = 6443
|
protocol = "TCP"
|
||||||
end_port = 6443
|
cidr_list = var.api_server_whitelist
|
||||||
protocol = "TCP"
|
ports = ["6443"]
|
||||||
cidr = each.value
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_security_group" "worker_sg" {
|
resource "exoscale_security_group" "worker_sg" {
|
||||||
@@ -128,64 +132,62 @@ resource "exoscale_security_group" "worker_sg" {
|
|||||||
description = "security group for kubernetes worker nodes"
|
description = "security group for kubernetes worker nodes"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_security_group_rule" "worker_sg_rule_ssh" {
|
resource "exoscale_security_group_rules" "worker_sg_rules" {
|
||||||
security_group_id = exoscale_security_group.worker_sg.id
|
security_group_id = exoscale_security_group.worker_sg.id
|
||||||
|
|
||||||
# SSH
|
# SSH
|
||||||
for_each = toset(var.ssh_whitelist)
|
ingress {
|
||||||
type = "INGRESS"
|
protocol = "TCP"
|
||||||
start_port = 22
|
cidr_list = var.ssh_whitelist
|
||||||
end_port = 22
|
ports = ["22"]
|
||||||
protocol = "TCP"
|
}
|
||||||
cidr = each.value
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "exoscale_security_group_rule" "worker_sg_rule_http" {
|
|
||||||
security_group_id = exoscale_security_group.worker_sg.id
|
|
||||||
|
|
||||||
# HTTP(S)
|
# HTTP(S)
|
||||||
for_each = toset(["80", "443"])
|
ingress {
|
||||||
type = "INGRESS"
|
protocol = "TCP"
|
||||||
start_port = each.value
|
cidr_list = ["0.0.0.0/0"]
|
||||||
end_port = each.value
|
ports = ["80", "443"]
|
||||||
protocol = "TCP"
|
}
|
||||||
cidr = "0.0.0.0/0"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Kubernetes Nodeport
|
||||||
resource "exoscale_security_group_rule" "worker_sg_rule_nodeport" {
|
ingress {
|
||||||
security_group_id = exoscale_security_group.worker_sg.id
|
protocol = "TCP"
|
||||||
|
cidr_list = var.nodeport_whitelist
|
||||||
# HTTP(S)
|
ports = ["30000-32767"]
|
||||||
for_each = toset(var.nodeport_whitelist)
|
|
||||||
type = "INGRESS"
|
|
||||||
start_port = 30000
|
|
||||||
end_port = 32767
|
|
||||||
protocol = "TCP"
|
|
||||||
cidr = each.value
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "exoscale_elastic_ip" "ingress_controller_lb" {
|
|
||||||
zone = var.zone
|
|
||||||
healthcheck {
|
|
||||||
mode = "http"
|
|
||||||
port = 80
|
|
||||||
uri = "/healthz"
|
|
||||||
interval = 10
|
|
||||||
timeout = 2
|
|
||||||
strikes_ok = 2
|
|
||||||
strikes_fail = 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "exoscale_elastic_ip" "control_plane_lb" {
|
resource "exoscale_ipaddress" "ingress_controller_lb" {
|
||||||
zone = var.zone
|
zone = var.zone
|
||||||
healthcheck {
|
healthcheck_mode = "http"
|
||||||
mode = "tcp"
|
healthcheck_port = 80
|
||||||
port = 6443
|
healthcheck_path = "/healthz"
|
||||||
interval = 10
|
healthcheck_interval = 10
|
||||||
timeout = 2
|
healthcheck_timeout = 2
|
||||||
strikes_ok = 2
|
healthcheck_strikes_ok = 2
|
||||||
strikes_fail = 3
|
healthcheck_strikes_fail = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resource "exoscale_secondary_ipaddress" "ingress_controller_lb" {
|
||||||
|
for_each = exoscale_compute.worker
|
||||||
|
|
||||||
|
compute_id = each.value.id
|
||||||
|
ip_address = exoscale_ipaddress.ingress_controller_lb.ip_address
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "exoscale_ipaddress" "control_plane_lb" {
|
||||||
|
zone = var.zone
|
||||||
|
healthcheck_mode = "tcp"
|
||||||
|
healthcheck_port = 6443
|
||||||
|
healthcheck_interval = 10
|
||||||
|
healthcheck_timeout = 2
|
||||||
|
healthcheck_strikes_ok = 2
|
||||||
|
healthcheck_strikes_fail = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "exoscale_secondary_ipaddress" "control_plane_lb" {
|
||||||
|
for_each = exoscale_compute.master
|
||||||
|
|
||||||
|
compute_id = each.value.id
|
||||||
|
ip_address = exoscale_ipaddress.control_plane_lb.ip_address
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user