Initial commit with basic Molecule
Change-Id: If55c8b62cb219e575857ba5395a48ddac5973e01
This commit is contained in:
parent
056377ad7c
commit
336caf4689
|
@ -0,0 +1 @@
|
|||
.tox
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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_playbook: vexxhost.atmosphere.site
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: false
|
||||
no_log: "{{ molecule_no_log }}"
|
||||
vars:
|
||||
ssh_port: 22
|
||||
stack_name: "{{ lookup('env', 'STACK_NAME') | default('atmosphere', True) }}"
|
||||
identity_file: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/id_rsa"
|
||||
tasks:
|
||||
- name: create stack
|
||||
openstack.cloud.stack:
|
||||
name: "{{ stack_name }}"
|
||||
template: heat/stack.yaml
|
||||
register: _os_stack
|
||||
|
||||
- debug:
|
||||
msg: "{{ _os_stack.stack }}"
|
||||
|
||||
- name: grab list of all ip addresses
|
||||
ansible.builtin.set_fact:
|
||||
key_pair: "{{ _os_stack.stack.outputs | json_query(key_query) | first }}"
|
||||
controller_ips: "{{ _os_stack.stack.outputs | community.general.json_query(controller_query) | first }}"
|
||||
storage_ips: "{{ _os_stack.stack.outputs | community.general.json_query(storage_query) | first }}"
|
||||
compute_ips: "{{ _os_stack.stack.outputs | community.general.json_query(compute_query) | first }}"
|
||||
vars:
|
||||
key_query: "[?output_key=='key_pair'].output_value"
|
||||
controller_query: "[?output_key=='controller_floating_ip_addresses'].output_value"
|
||||
storage_query: "[?output_key=='storage_floating_ip_addresses'].output_value"
|
||||
compute_query: "[?output_key=='compute_floating_ip_addresses'].output_value"
|
||||
|
||||
- name: wait for systems to go up
|
||||
ansible.builtin.wait_for:
|
||||
port: "22"
|
||||
host: "{{ item }}"
|
||||
search_regex: SSH
|
||||
timeout: 60
|
||||
loop: "{{ controller_ips + storage_ips + compute_ips }}"
|
||||
|
||||
- name: generate private key file
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ identity_file }}"
|
||||
content: "{{ key_pair }}"
|
||||
mode: 0600
|
||||
|
||||
- name: generate instance config file
|
||||
copy:
|
||||
content: "{{ instance_config | to_yaml }}"
|
||||
dest: "{{ molecule_instance_config }}"
|
||||
vars:
|
||||
base_instance_config: &instance_config
|
||||
user: "ubuntu"
|
||||
port: "{{ ssh_port }}"
|
||||
identity_file: "{{ identity_file }}"
|
||||
instance_config:
|
||||
- <<: *instance_config
|
||||
instance: "ctl1"
|
||||
address: "{{ controller_ips[0] }}"
|
||||
- <<: *instance_config
|
||||
instance: "ctl2"
|
||||
address: "{{ controller_ips[1] }}"
|
||||
- <<: *instance_config
|
||||
instance: "ctl3"
|
||||
address: "{{ controller_ips[2] }}"
|
||||
- <<: *instance_config
|
||||
instance: "nvme1"
|
||||
address: "{{ storage_ips[0] }}"
|
||||
- <<: *instance_config
|
||||
instance: "nvme2"
|
||||
address: "{{ storage_ips[1] }}"
|
||||
- <<: *instance_config
|
||||
instance: "nvme3"
|
||||
address: "{{ storage_ips[2] }}"
|
||||
- <<: *instance_config
|
||||
instance: "kvm1"
|
||||
address: "{{ compute_ips[0] }}"
|
||||
- <<: *instance_config
|
||||
instance: "kvm2"
|
||||
address: "{{ compute_ips[1] }}"
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: false
|
||||
no_log: "{{ molecule_no_log }}"
|
||||
vars:
|
||||
stack_name: "{{ lookup('env', 'STACK_NAME') | default('atmosphere', True) }}"
|
||||
tasks:
|
||||
- os_stack:
|
||||
name: "{{ stack_name }}"
|
||||
state: absent
|
||||
|
||||
- file:
|
||||
path: "{{ molecule_instance_config }}"
|
||||
state: absent
|
|
@ -0,0 +1,126 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
heat_template_version: 2016-10-14
|
||||
|
||||
parameters:
|
||||
name:
|
||||
type: string
|
||||
|
||||
index:
|
||||
type: number
|
||||
|
||||
image:
|
||||
type: string
|
||||
default: Ubuntu 20.04.3 LTS (x86_64) [2021-10-04]
|
||||
constraints:
|
||||
- custom_constraint: glance.image
|
||||
|
||||
instance_type:
|
||||
type: string
|
||||
default: v3-standard-4
|
||||
constraints:
|
||||
- custom_constraint: nova.flavor
|
||||
|
||||
internal_network:
|
||||
type: string
|
||||
constraints:
|
||||
- custom_constraint: neutron.network
|
||||
|
||||
key_name:
|
||||
type: string
|
||||
constraints:
|
||||
- custom_constraint: nova.keypair
|
||||
|
||||
security_group:
|
||||
type: string
|
||||
constraints:
|
||||
- custom_constraint: neutron.security_group
|
||||
|
||||
public_network:
|
||||
type: string
|
||||
default: public
|
||||
constraints:
|
||||
- custom_constraint: neutron.network
|
||||
|
||||
external_network:
|
||||
type: string
|
||||
constraints:
|
||||
- custom_constraint: neutron.network
|
||||
|
||||
extra_volumes_count:
|
||||
type: number
|
||||
default: 0
|
||||
|
||||
extra_volumes_size:
|
||||
type: number
|
||||
default: 0
|
||||
|
||||
conditions:
|
||||
has_extra_volumes:
|
||||
not:
|
||||
equals:
|
||||
- get_param: extra_volumes_count
|
||||
- 0
|
||||
|
||||
resources:
|
||||
internal_port:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: internal_network }
|
||||
port_security_enabled: false
|
||||
|
||||
floating_ip:
|
||||
type: OS::Neutron::FloatingIP
|
||||
properties:
|
||||
floating_network: { get_param: public_network }
|
||||
port_id: { get_resource: internal_port }
|
||||
|
||||
external_port:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: external_network }
|
||||
security_groups:
|
||||
- { get_param: security_group }
|
||||
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
name:
|
||||
yaql:
|
||||
expression: concat($.data.name, str($.data.index + 1))
|
||||
data:
|
||||
name: { get_param: name }
|
||||
index: { get_param: index }
|
||||
image: { get_param: image }
|
||||
flavor: { get_param: instance_type }
|
||||
key_name: { get_param: key_name }
|
||||
networks:
|
||||
- port: { get_resource: internal_port }
|
||||
- port: { get_resource: external_port }
|
||||
|
||||
volumes:
|
||||
type: OS::Heat::ResourceGroup
|
||||
condition: has_extra_volumes
|
||||
properties:
|
||||
count: { get_param: extra_volumes_count }
|
||||
resource_def:
|
||||
type: volume.yaml
|
||||
properties:
|
||||
instance_uuid: { get_resource: server }
|
||||
volume_size: { get_param: extra_volumes_size }
|
||||
|
||||
outputs:
|
||||
floating_ip_address:
|
||||
value: { get_attr: [floating_ip, floating_ip_address] }
|
|
@ -0,0 +1,184 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
heat_template_version: 2016-10-14
|
||||
|
||||
parameters:
|
||||
internal_cidr:
|
||||
type: string
|
||||
default: 10.96.240.0/24
|
||||
constraints:
|
||||
- custom_constraint: net_cidr
|
||||
|
||||
external_cidr:
|
||||
type: string
|
||||
default: 10.96.250.0/24
|
||||
constraints:
|
||||
- custom_constraint: net_cidr
|
||||
|
||||
public_network:
|
||||
type: string
|
||||
default: public
|
||||
constraints:
|
||||
- custom_constraint: neutron.network
|
||||
|
||||
image:
|
||||
type: string
|
||||
default: Ubuntu 20.04.3 LTS (x86_64) [2021-10-04]
|
||||
constraints:
|
||||
- custom_constraint: glance.image
|
||||
|
||||
instance_type:
|
||||
type: string
|
||||
default: v3-standard-4
|
||||
constraints:
|
||||
- custom_constraint: nova.flavor
|
||||
|
||||
resources:
|
||||
security_group:
|
||||
type: OS::Neutron::SecurityGroup
|
||||
properties:
|
||||
rules:
|
||||
- protocol: tcp
|
||||
remote_ip_prefix: 0.0.0.0/0
|
||||
- protocol: udp
|
||||
remote_ip_prefix: 0.0.0.0/0
|
||||
- protocol: icmp
|
||||
remote_ip_prefix: 0.0.0.0/0
|
||||
|
||||
router:
|
||||
type: OS::Neutron::Router
|
||||
properties:
|
||||
external_gateway_info:
|
||||
network: { get_param: public_network }
|
||||
|
||||
internal_network:
|
||||
type: OS::Neutron::Net
|
||||
|
||||
internal_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
network: { get_resource: internal_network }
|
||||
cidr: { get_param: internal_cidr }
|
||||
dns_nameservers: ["1.1.1.1"]
|
||||
|
||||
internal_network_router_interface:
|
||||
type: OS::Neutron::RouterInterface
|
||||
properties:
|
||||
router: { get_resource: router }
|
||||
subnet: { get_resource: internal_subnet }
|
||||
|
||||
internal_network_vip:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_resource: internal_network }
|
||||
|
||||
internal_network_vip_floating_ip:
|
||||
type: OS::Neutron::FloatingIP
|
||||
depends_on:
|
||||
- internal_network_router_interface
|
||||
properties:
|
||||
floating_network: { get_param: public_network }
|
||||
port_id: { get_resource: internal_network_vip }
|
||||
|
||||
external_network:
|
||||
type: OS::Neutron::Net
|
||||
|
||||
external_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
network: { get_resource: external_network }
|
||||
cidr: { get_param: external_cidr }
|
||||
dns_nameservers: ["1.1.1.1"]
|
||||
gateway_ip: null
|
||||
|
||||
external_network_vip:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_resource: external_network }
|
||||
|
||||
key_pair:
|
||||
type: OS::Nova::KeyPair
|
||||
properties:
|
||||
name: { get_param: OS::stack_id }
|
||||
save_private_key: true
|
||||
|
||||
controller:
|
||||
type: OS::Heat::ResourceGroup
|
||||
depends_on:
|
||||
- internal_network_router_interface
|
||||
properties:
|
||||
count: 3
|
||||
resource_def:
|
||||
type: server.yaml
|
||||
properties:
|
||||
name: ctl
|
||||
index: "%index%"
|
||||
image: { get_param: image }
|
||||
instance_type: { get_param: instance_type }
|
||||
key_name: { get_resource: key_pair }
|
||||
security_group: { get_resource: security_group }
|
||||
internal_network: { get_resource: internal_network }
|
||||
public_network: { get_param: public_network }
|
||||
external_network: { get_resource: external_network }
|
||||
|
||||
storage:
|
||||
type: OS::Heat::ResourceGroup
|
||||
depends_on:
|
||||
- internal_network_router_interface
|
||||
properties:
|
||||
count: 3
|
||||
resource_def:
|
||||
type: server.yaml
|
||||
properties:
|
||||
name: nvme
|
||||
index: "%index%"
|
||||
image: { get_param: image }
|
||||
instance_type: { get_param: instance_type }
|
||||
key_name: { get_resource: key_pair }
|
||||
security_group: { get_resource: security_group }
|
||||
internal_network: { get_resource: internal_network }
|
||||
public_network: { get_param: public_network }
|
||||
external_network: { get_resource: external_network }
|
||||
extra_volumes_count: 3
|
||||
extra_volumes_size: 40
|
||||
|
||||
compute:
|
||||
type: OS::Heat::ResourceGroup
|
||||
depends_on:
|
||||
- internal_network_router_interface
|
||||
properties:
|
||||
count: 2
|
||||
resource_def:
|
||||
type: server.yaml
|
||||
properties:
|
||||
name: kvm
|
||||
index: "%index%"
|
||||
image: { get_param: image }
|
||||
instance_type: { get_param: instance_type }
|
||||
key_name: { get_resource: key_pair }
|
||||
security_group: { get_resource: security_group }
|
||||
internal_network: { get_resource: internal_network }
|
||||
public_network: { get_param: public_network }
|
||||
external_network: { get_resource: external_network }
|
||||
|
||||
outputs:
|
||||
controller_floating_ip_addresses:
|
||||
value: { get_attr: [controller, floating_ip_address] }
|
||||
storage_floating_ip_addresses:
|
||||
value: { get_attr: [storage, floating_ip_address] }
|
||||
compute_floating_ip_addresses:
|
||||
value: { get_attr: [compute, floating_ip_address] }
|
||||
key_pair:
|
||||
value: { get_attr: [key_pair, private_key] }
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
heat_template_version: 2016-10-14
|
||||
|
||||
parameters:
|
||||
instance_uuid:
|
||||
type: string
|
||||
|
||||
volume_size:
|
||||
type: number
|
||||
|
||||
resources:
|
||||
volume:
|
||||
type: OS::Cinder::Volume
|
||||
properties:
|
||||
size: { get_param: volume_size }
|
||||
|
||||
volume_attachment:
|
||||
type: OS::Cinder::VolumeAttachment
|
||||
properties:
|
||||
instance_uuid: { get_param: instance_uuid }
|
||||
volume_id: { get_resource: volume }
|
|
@ -0,0 +1,133 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
dependency:
|
||||
name: galaxy
|
||||
driver:
|
||||
name: delegated
|
||||
platforms:
|
||||
- name: ctl1
|
||||
groups: &controller_groups
|
||||
- controllers
|
||||
- cephs
|
||||
- ceph_mons
|
||||
- ceph_mgrs
|
||||
- name: ctl2
|
||||
groups: *controller_groups
|
||||
- name: ctl3
|
||||
groups: *controller_groups
|
||||
- name: nvme1
|
||||
groups: &nvme_groups
|
||||
- cephs
|
||||
- ceph_osds
|
||||
- name: nvme2
|
||||
groups: *nvme_groups
|
||||
- name: nvme3
|
||||
groups: *nvme_groups
|
||||
- name: kvm1
|
||||
groups: &kvm_groups
|
||||
- computes
|
||||
- name: kvm2
|
||||
groups: *kvm_groups
|
||||
provisioner:
|
||||
name: ansible
|
||||
env:
|
||||
ANSIBLE_PIPELINING: "True"
|
||||
inventory:
|
||||
group_vars:
|
||||
all:
|
||||
atmosphere_image_repository: us-docker.pkg.dev/vexxhost-infra/openstack
|
||||
kubernetes_hostname: 10.96.240.10
|
||||
controllers:
|
||||
kubernetes_keepalived_vrid: 42
|
||||
kubernetes_keepalived_interface: ens3
|
||||
kubernetes_keepalived_vip: 10.96.240.10
|
||||
openstack_helm_endpoints_region_name: RegionOne
|
||||
# Memcached
|
||||
openstack_helm_endpoints_memcached_secret_key: 7XsFMtMoUT9c8eCqbBNJycqwIepvLYzfOI2kpYhBUJSl2X5RDHiyolaQqQp36nVR
|
||||
# RabbitMQ
|
||||
openstack_helm_endpoints_rabbitmq_erlang_cookie: openstack-cookie
|
||||
openstack_helm_endpoints_rabbitmq_admin_password: password123
|
||||
# Keystone
|
||||
openstack_helm_endpoints_keystone_api_host: "identity.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_keystone_mariadb_password: keystone-mariadb-password
|
||||
openstack_helm_endpoints_keystone_rabbitmq_password: keystone-rabbitmq-password
|
||||
openstack_helm_endpoints_keystone_admin_password: keystone-admin-password
|
||||
# Glance
|
||||
openstack_helm_endpoints_glance_api_host: "image.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_glance_mariadb_password: glance-mariadb-password
|
||||
openstack_helm_endpoints_glance_rabbitmq_password: glance-rabbitmq-password
|
||||
openstack_helm_endpoints_glance_keystone_password: glance-keystone-password
|
||||
# Cinder
|
||||
openstack_helm_endpoints_cinder_api_host: "volume.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_cinder_mariadb_password: cinder-mariadb-password
|
||||
openstack_helm_endpoints_cinder_rabbitmq_password: cinder-rabbitmq-password
|
||||
openstack_helm_endpoints_cinder_keystone_password: cinder-keystone-password
|
||||
# Placement
|
||||
openstack_helm_endpoints_placement_api_host: "placement.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_placement_keystone_password: placement-keystone-password
|
||||
openstack_helm_endpoints_placement_mariadb_password: placement-mariadb-password
|
||||
# Neutron
|
||||
openstack_helm_endpoints_neutron_api_host: "network.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_neutron_mariadb_password: neutron-mariadb-password
|
||||
openstack_helm_endpoints_neutron_rabbitmq_password: neutron-rabbitmq-password
|
||||
openstack_helm_endpoints_neutron_keystone_password: neutron-keystone-password
|
||||
openstack_helm_endpoints_neutron_metadata_secret: neutron-metadata-secret
|
||||
openstack_helm_neutron_values:
|
||||
conf:
|
||||
auto_bridge_add:
|
||||
br-ex: ens4
|
||||
# Nova
|
||||
openstack_helm_endpoints_nova_api_host: "compute.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_nova_novnc_host: "vnc.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_nova_mariadb_password: nova-mariadb-password
|
||||
openstack_helm_endpoints_nova_rabbitmq_password: nova-rabbitmq-password
|
||||
openstack_helm_endpoints_nova_keystone_password: nova-keystone-password
|
||||
# Ironic
|
||||
openstack_helm_endpoints_ironic_api_host: "baremetal.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_ironic_mariadb_password: ironic-mariadb-password
|
||||
openstack_helm_endpoints_ironic_rabbitmq_password: ironic-rabbitmq-password
|
||||
openstack_helm_endpoints_ironic_keystone_password: ironic-keystone-password
|
||||
# Designate
|
||||
openstack_helm_endpoints_designate_api_host: "dns.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_designate_mariadb_password: designate-mariadb-password
|
||||
openstack_helm_endpoints_designate_rabbitmq_password: designate-rabbitmq-password
|
||||
openstack_helm_endpoints_designate_keystone_password: designate-keystone-password
|
||||
# Octavia
|
||||
openstack_helm_endpoints_octavia_api_host: "load-balancer.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_octavia_mariadb_password: octavia-mariadb-password
|
||||
openstack_helm_endpoints_octavia_rabbitmq_password: octavia-rabbitmq-password
|
||||
openstack_helm_endpoints_octavia_keystone_password: octavia-keystone-password
|
||||
# Heat
|
||||
openstack_helm_endpoints_heat_api_host: "orchestration.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_heat_keystone_password: heat-keystone-password
|
||||
openstack_helm_endpoints_heat_trustee_keystone_password: heat-trustee-keystone-password
|
||||
openstack_helm_endpoints_heat_stack_user_keystone_password: heat-stack-user-keystone-password
|
||||
openstack_helm_endpoints_heat_mariadb_password: heat-mariadb-password
|
||||
openstack_helm_endpoints_heat_rabbitmq_password: heat-rabbitmq-password
|
||||
openstack_helm_endpoints_heat_cfn_api_host: "cloudformation.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_heat_auth_encryption_key: heat-auth-encryption-key
|
||||
# Horizon
|
||||
openstack_helm_endpoints_horizon_api_host: "dashboard.{{ hostvars['ctl1']['ansible_host'].replace('.', '-') }}.nip.io"
|
||||
openstack_helm_endpoints_horizon_mariadb_password: horizon-mariadb-password
|
||||
cephs:
|
||||
ceph_mon_fsid: 441193d8-fed9-485b-87f4-09245ddc1fe7
|
||||
ceph_mon_public_network: 10.96.240.0/24
|
||||
ceph_osds:
|
||||
ceph_osd_devices:
|
||||
- /dev/vdb
|
||||
- /dev/vdc
|
||||
- /dev/vdd
|
||||
verifier:
|
||||
name: testinfra
|
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- hosts: all
|
||||
tasks:
|
||||
# The apt module can not be used for this since it installs python-apt
|
||||
# which can not work until this command fixes the cache.
|
||||
- name: Update apt cache
|
||||
become: yes
|
||||
command: apt-get update
|
|
@ -0,0 +1 @@
|
|||
openstacksdk
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- hosts: all
|
||||
become: true
|
||||
roles:
|
||||
- role: containerd
|
||||
- role: kubernetes
|
||||
|
||||
- hosts: controllers
|
||||
become: true
|
||||
roles:
|
||||
- helm
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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_playbook: vexxhost.atmosphere.kubernetes
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
containerd_pause_image: k8s.gcr.io/pause:3.5
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Restart containerd
|
||||
ansible.builtin.service:
|
||||
name: containerd
|
||||
state: restarted
|
|
@ -0,0 +1,48 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Add repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb {{ containerd_repository_url }} {{ ansible_distribution_release }} main"
|
||||
state: present
|
||||
when:
|
||||
- containerd_repository_url is defined
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
name: containerd
|
||||
state: present
|
||||
|
||||
- name: Create folder for configuration
|
||||
ansible.builtin.file:
|
||||
path: /etc/containerd
|
||||
state: directory
|
||||
notify:
|
||||
- Restart containerd
|
||||
|
||||
- name: Update pause image in configuration
|
||||
ansible.builtin.template:
|
||||
src: config.toml.j2
|
||||
dest: /etc/containerd/config.toml
|
||||
notify:
|
||||
- Restart containerd
|
||||
|
||||
- name: Force any restarts if necessary
|
||||
meta: flush_handlers
|
||||
|
||||
- name: Enable and start service
|
||||
ansible.builtin.service:
|
||||
name: containerd
|
||||
enabled: true
|
||||
state: started
|
|
@ -0,0 +1,5 @@
|
|||
version = 2
|
||||
|
||||
[plugins]
|
||||
[plugins."io.containerd.grpc.v1.cri"]
|
||||
sandbox_image = "{{ containerd_pause_image }}"
|
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
helm_repository_apt_key: https://baltocdn.com/helm/signing.asc
|
||||
helm_repository_url: https://baltocdn.com/helm/stable/debian/
|
||||
helm_version: 3.8.0
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: add apt key
|
||||
ansible.builtin.apt_key:
|
||||
url: "{{ helm_repository_apt_key }}"
|
||||
state: present
|
||||
|
||||
- name: configure version pinning
|
||||
ansible.builtin.template:
|
||||
src: apt-preferences.j2
|
||||
dest: /etc/apt/preferences.d/helm
|
||||
mode: 0644
|
||||
|
||||
- name: Add package repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb {{ helm_repository_url }} all main"
|
||||
state: present
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
name: ["helm"]
|
||||
install_recommends: false
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Gather operating system facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- min
|
||||
|
||||
- name: Install packages using operating system specific process
|
||||
ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml"
|
||||
|
||||
- name: install helm diff
|
||||
kubernetes.core.helm_plugin:
|
||||
plugin_path: https://github.com/databus23/helm-diff
|
||||
state: present
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Add package repository
|
||||
ansible.builtin.yum:
|
||||
name: "https://harbottle.gitlab.io/harbottle-main/{{ ansible_distribution_major_version }}/x86_64/harbottle-main-release.rpm"
|
||||
disable_gpg_check: true
|
||||
state: present
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.yum:
|
||||
name: helm
|
||||
state: present
|
|
@ -0,0 +1,3 @@
|
|||
Package: helm
|
||||
Pin: version {{ helm_version }}-*
|
||||
Pin-Priority: 1000
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
kubernetes_repo_url: "{{ _kubernetes_upstream_apt_repository }}"
|
||||
kubernetes_version: 1.22.7
|
||||
|
||||
kubernetes_kernel_modules:
|
||||
- br_netfilter
|
||||
|
||||
kubernetes_sysctls:
|
||||
- name: net.ipv4.ip_forward
|
||||
value: 1
|
||||
- name: net.ipv4.tcp_l3mdev_accept
|
||||
value: 1
|
||||
- name: net.ipv4.udp_l3mdev_accept
|
||||
value: 1
|
||||
- name: net.bridge.bridge-nf-call-iptables
|
||||
value: 1
|
||||
- name: net.bridge.bridge-nf-call-ip6tables
|
||||
value: 1
|
||||
- name: net.ipv4.conf.all.rp_filter
|
||||
value: 0
|
||||
|
||||
kubernetes_control_plane_group: controllers
|
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: haproxy
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- image: haproxy:2.5
|
||||
name: haproxy
|
||||
livenessProbe:
|
||||
failureThreshold: 8
|
||||
httpGet:
|
||||
host: localhost
|
||||
path: /healthz
|
||||
port: 6443
|
||||
scheme: HTTPS
|
||||
volumeMounts:
|
||||
- mountPath: /usr/local/etc/haproxy/haproxy.cfg
|
||||
name: haproxyconf
|
||||
readOnly: true
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /etc/haproxy/haproxy.cfg
|
||||
type: FileOrCreate
|
||||
name: haproxyconf
|
||||
status: {}
|
|
@ -0,0 +1,32 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: keepalived
|
||||
namespace: kube-system
|
||||
spec:
|
||||
containers:
|
||||
- name: keepalived
|
||||
image: us-docker.pkg.dev/vexxhost-infra/openstack/keepalived:2.0.19
|
||||
command: ["keepalived", "-f", "/etc/keepalived/keepalived.conf", "--dont-fork", "--log-console", "--log-detail", "--dump-conf"]
|
||||
resources: {}
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_ADMIN
|
||||
- NET_BROADCAST
|
||||
- NET_RAW
|
||||
volumeMounts:
|
||||
- mountPath: /etc/keepalived/keepalived.conf
|
||||
name: config
|
||||
- mountPath: /etc/keepalived/check_apiserver.sh
|
||||
name: check
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /etc/keepalived/keepalived.conf
|
||||
name: config
|
||||
- hostPath:
|
||||
path: /etc/keepalived/check_apiserver.sh
|
||||
name: check
|
||||
status: {}
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
dependencies:
|
||||
- role: containerd
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Determine node to use for bootstrapping cluster
|
||||
block:
|
||||
- name: Check if any control plane is bootstrapped
|
||||
ansible.builtin.stat:
|
||||
path: /etc/kubernetes/admin.conf
|
||||
register: _kubernetes_stat
|
||||
loop: "{{ groups[kubernetes_control_plane_group] }}"
|
||||
delegate_to: "{{ item }}"
|
||||
delegate_facts: True
|
||||
|
||||
- name: Pick node from pre-existing cluster
|
||||
ansible.builtin.set_fact:
|
||||
_kubernetes_bootstrap_node: "{{ _kubernetes_stat.results | selectattr('stat.exists', 'equalto', true) | map(attribute='item') | first }}"
|
||||
when: _kubernetes_stat.results | selectattr('stat.exists', 'equalto', true) | length > 0
|
||||
|
||||
- name: Select first node to initialize cluster
|
||||
ansible.builtin.set_fact:
|
||||
_kubernetes_bootstrap_node: "{{ groups[kubernetes_control_plane_group] | first }}"
|
||||
when: _kubernetes_stat.results | selectattr('stat.exists', 'equalto', true) | length == 0
|
||||
|
||||
- name: Print selected bootstrap node
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ _kubernetes_bootstrap_node }}"
|
||||
|
||||
- name: Upload cluster configuration for bootstrap node
|
||||
ansible.builtin.template:
|
||||
src: kubeadm.yaml.j2
|
||||
dest: /etc/kubernetes/kubeadm.yaml
|
||||
when: inventory_hostname == _kubernetes_bootstrap_node
|
||||
|
||||
- name: Initialize cluster
|
||||
throttle: 1
|
||||
ansible.builtin.shell: |
|
||||
kubeadm init --config /etc/kubernetes/kubeadm.yaml --upload-certs
|
||||
args:
|
||||
creates: /etc/kubernetes/admin.conf
|
||||
environment:
|
||||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
when: inventory_hostname == _kubernetes_bootstrap_node
|
||||
|
||||
- name: Join cluster
|
||||
ansible.builtin.include_tasks: join-cluster.yml
|
||||
when: inventory_hostname != _kubernetes_bootstrap_node
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Upload configuration for Keepalived
|
||||
block:
|
||||
- name: Create folder
|
||||
ansible.builtin.file:
|
||||
dest: /etc/keepalived
|
||||
state: directory
|
||||
- name: Upload configuration
|
||||
ansible.builtin.template:
|
||||
src: keepalived.conf.j2
|
||||
dest: /etc/keepalived/keepalived.conf
|
||||
- name: Upload health check
|
||||
ansible.builtin.template:
|
||||
src: check_apiserver.sh.j2
|
||||
dest: /etc/keepalived/check_apiserver.sh
|
||||
mode: 0755
|
||||
- name: Upload Kubernetes manifest
|
||||
ansible.builtin.copy:
|
||||
src: keepalived.yaml
|
||||
dest: /etc/kubernetes/manifests/keepalived.yaml
|
||||
|
||||
- name: Upload configuration for HAproxy
|
||||
block:
|
||||
- name: Create folder
|
||||
ansible.builtin.file:
|
||||
dest: /etc/haproxy
|
||||
state: directory
|
||||
- name: Upload configuration
|
||||
ansible.builtin.template:
|
||||
src: haproxy.cfg.j2
|
||||
dest: /etc/haproxy/haproxy.cfg
|
||||
- name: Upload Kubernetes manifest
|
||||
ansible.builtin.copy:
|
||||
src: haproxy.yaml
|
||||
dest: /etc/kubernetes/manifests/haproxy.yaml
|
||||
|
||||
- name: Bootstrap cluster
|
||||
include_tasks: bootstrap-cluster.yml
|
||||
|
||||
- name: create folder for admin configuration
|
||||
ansible.builtin.file:
|
||||
path: /root/.kube
|
||||
state: directory
|
||||
|
||||
- name: copy admin configuration file
|
||||
ansible.builtin.copy:
|
||||
src: /etc/kubernetes/admin.conf
|
||||
dest: /root/.kube/config
|
||||
mode: 0600
|
||||
remote_src: true
|
||||
|
||||
- name: install pip
|
||||
ansible.builtin.apt:
|
||||
name: python3-pip
|
||||
install_recommends: false
|
||||
|
||||
- name: install kubernetes python package
|
||||
ansible.builtin.pip:
|
||||
name: kubernetes
|
||||
|
||||
- name: Allow workloads on control plane nodes
|
||||
run_once: true
|
||||
ansible.builtin.shell: |
|
||||
kubectl taint nodes --all node-role.kubernetes.io/master-
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Add labels to control plane nodes
|
||||
kubernetes.core.k8s:
|
||||
state: patched
|
||||
kind: Node
|
||||
name: "{{ inventory_hostname_short }}"
|
||||
definition:
|
||||
metadata:
|
||||
labels:
|
||||
openstack-control-plane: enabled
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Check if the node is already part of the cluster
|
||||
ansible.builtin.stat:
|
||||
path: /etc/kubernetes/kubelet.conf
|
||||
register: _stat_etc_kubernetes_kubelet_conf
|
||||
|
||||
- name: Generate control-plane certificates for joining cluster
|
||||
run_once: true
|
||||
delegate_to: "{{ _kubernetes_bootstrap_node | default(groups[kubernetes_control_plane_group][0]) }}"
|
||||
ansible.builtin.shell: |
|
||||
kubeadm init phase upload-certs --upload-certs 2>/dev/null | grep -v upload-certs
|
||||
changed_when: false
|
||||
register: _kubeadm_init_upload_certs
|
||||
when:
|
||||
- not _stat_etc_kubernetes_kubelet_conf.stat.exists
|
||||
- inventory_hostname in groups[kubernetes_control_plane_group]
|
||||
|
||||
- name: Retrieve SHA256 certificate hash
|
||||
run_once: true
|
||||
delegate_to: "{{ _kubernetes_bootstrap_node | default(groups[kubernetes_control_plane_group][0]) }}"
|
||||
community.crypto.x509_certificate_info:
|
||||
path: /etc/kubernetes/pki/ca.crt
|
||||
register: _kubeadm_certificate_info
|
||||
when:
|
||||
- not _stat_etc_kubernetes_kubelet_conf.stat.exists
|
||||
|
||||
- name: Generate token for joining cluster
|
||||
run_once: true
|
||||
delegate_to: "{{ _kubernetes_bootstrap_node | default(groups[kubernetes_control_plane_group][0]) }}"
|
||||
ansible.builtin.shell: |
|
||||
kubeadm token create
|
||||
register: _kubeadm_token_create
|
||||
when:
|
||||
- not _stat_etc_kubernetes_kubelet_conf.stat.exists
|
||||
|
||||
- name: Upload kubeadm configuration
|
||||
ansible.builtin.template:
|
||||
src: kubeadm.yaml.j2
|
||||
dest: /etc/kubernetes/kubeadm.yaml
|
||||
when:
|
||||
- not _stat_etc_kubernetes_kubelet_conf.stat.exists
|
||||
|
||||
- name: Join cluster
|
||||
ansible.builtin.shell: |
|
||||
kubeadm join --config /etc/kubernetes/kubeadm.yaml \
|
||||
--ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests
|
||||
environment:
|
||||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
args:
|
||||
creates: /etc/kubernetes/kubelet.conf
|
|
@ -0,0 +1,124 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Add repository keys
|
||||
ansible.builtin.copy:
|
||||
src: apt-key.gpg
|
||||
dest: /usr/share/keyrings/kubernetes-archive-keyring.gpg
|
||||
when:
|
||||
- kubernetes_repo_url == _kubernetes_upstream_apt_repository
|
||||
|
||||
- name: Add repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb {% if kubernetes_repo_url == _kubernetes_upstream_apt_repository %}[signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg]{% endif %} {{ kubernetes_repo_url }} kubernetes-xenial main"
|
||||
state: present
|
||||
|
||||
- name: Setup version pins
|
||||
ansible.builtin.template:
|
||||
src: apt-preferences.j2
|
||||
dest: /etc/apt/preferences.d/kubernetes
|
||||
mode: 0644
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "containerd"
|
||||
- "kubeadm={{ kubernetes_version }}-00"
|
||||
- "kubectl={{ kubernetes_version }}-00"
|
||||
- "kubelet={{ kubernetes_version }}-00"
|
||||
state: present
|
||||
|
||||
- name: Enable kernel modules on-boot
|
||||
ansible.builtin.template:
|
||||
src: modules-load.conf.j2
|
||||
dest: /etc/modules-load.d/k8s.conf
|
||||
|
||||
- name: Enable kernel modules in runtime
|
||||
community.general.modprobe:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop: "{{ kubernetes_kernel_modules }}"
|
||||
|
||||
- name: Configure sysctl values
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item.name }}"
|
||||
value: "{{ item.value }}"
|
||||
state: present
|
||||
loop: "{{ kubernetes_sysctls }}"
|
||||
|
||||
- name: Check swap status
|
||||
ansible.builtin.command: /sbin/swapon -s
|
||||
changed_when: false
|
||||
register: _swapon
|
||||
|
||||
- name: Disable swap
|
||||
ansible.builtin.command: /sbin/swapoff -a
|
||||
ignore_errors: "{{ ansible_check_mode }}"
|
||||
when:
|
||||
- _swapon.stdout
|
||||
|
||||
- name: Remove swapfile from /etc/fstab
|
||||
ansible.posix.mount:
|
||||
name: "{{ item }}"
|
||||
fstype: swap
|
||||
state: absent
|
||||
with_items:
|
||||
- swap
|
||||
- none
|
||||
|
||||
- name: Configure short hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ inventory_hostname_short }}"
|
||||
|
||||
- name: Ensure hostname inside hosts file
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/hosts
|
||||
regexp: '^127\.0\.1\.1'
|
||||
line: 127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}
|
||||
|
||||
- name: Setup control plane
|
||||
when: inventory_hostname in groups[kubernetes_control_plane_group]
|
||||
ansible.builtin.include_tasks: control-plane.yml
|
||||
|
||||
- name: Setup nodes
|
||||
when: inventory_hostname not in groups[kubernetes_control_plane_group]
|
||||
ansible.builtin.include_tasks: nodes.yml
|
||||
|
||||
- name: Add labels to control plane nodes
|
||||
delegate_to: "{{ groups[kubernetes_control_plane_group][0] }}"
|
||||
kubernetes.core.k8s:
|
||||
state: patched
|
||||
kind: Node
|
||||
name: "{{ inventory_hostname_short }}"
|
||||
definition:
|
||||
metadata:
|
||||
labels:
|
||||
openstack-control-plane: enabled
|
||||
openvswitch: enabled
|
||||
when:
|
||||
- inventory_hostname in groups['controllers']
|
||||
|
||||
- name: Add labels to compute nodes
|
||||
delegate_to: "{{ groups[kubernetes_control_plane_group][0] }}"
|
||||
kubernetes.core.k8s:
|
||||
state: patched
|
||||
kind: Node
|
||||
name: "{{ inventory_hostname_short }}"
|
||||
definition:
|
||||
metadata:
|
||||
labels:
|
||||
openstack-compute-node: enabled
|
||||
openvswitch: enabled
|
||||
when:
|
||||
- inventory_hostname in groups['computes']
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- name: Check if Kubernetes is already deployed
|
||||
stat:
|
||||
path: /etc/kubernetes/kubelet.conf
|
||||
register: _kubernetes_kubelet
|
||||
|
||||
- name: Join cluster
|
||||
when: not _kubernetes_kubelet.stat.exists
|
||||
ansible.builtin.include_tasks: join-cluster.yml
|
|
@ -0,0 +1,11 @@
|
|||
Package: kubectl
|
||||
Pin: version {{ kubernetes_version }}-00
|
||||
Pin-Priority: 1000
|
||||
|
||||
Package: kubeadm
|
||||
Pin: version {{ kubernetes_version }}-00
|
||||
Pin-Priority: 1000
|
||||
|
||||
Package: kubelet
|
||||
Pin: version {{ kubernetes_version }}-00
|
||||
Pin-Priority: 1000
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
errorExit() {
|
||||
echo "*** $*" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
curl --silent --max-time 2 --insecure https://localhost:16443/ -o /dev/null || errorExit "Error GET https://localhost:16443/"
|
||||
if ip addr | grep -q {{ kubernetes_keepalived_vip }}; then
|
||||
curl --silent --max-time 2 --insecure https://{{ kubernetes_keepalived_vip }}:6443/ -o /dev/null || errorExit "Error GET https://{{ kubernetes_keepalived_vip }}:6443/"
|
||||
fi
|
|
@ -0,0 +1,51 @@
|
|||
# /etc/haproxy/haproxy.cfg
|
||||
#---------------------------------------------------------------------
|
||||
# Global settings
|
||||
#---------------------------------------------------------------------
|
||||
global
|
||||
log /dev/log local0
|
||||
log /dev/log local1 notice
|
||||
daemon
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# common defaults that all the 'listen' and 'backend' sections will
|
||||
# use if not designated in their block
|
||||
#---------------------------------------------------------------------
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
option httplog
|
||||
option dontlognull
|
||||
option http-server-close
|
||||
option forwardfor except 127.0.0.0/8
|
||||
option redispatch
|
||||
retries 1
|
||||
timeout http-request 10s
|
||||
timeout queue 20s
|
||||
timeout connect 5s
|
||||
timeout client 20s
|
||||
timeout server 20s
|
||||
timeout http-keep-alive 10s
|
||||
timeout check 10s
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# apiserver frontend which proxys to the masters
|
||||
#---------------------------------------------------------------------
|
||||
frontend apiserver
|
||||
bind *:6443
|
||||
mode tcp
|
||||
option tcplog
|
||||
default_backend apiserver
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# round robin balancing for apiserver
|
||||
#---------------------------------------------------------------------
|
||||
backend apiserver
|
||||
option httpchk GET /healthz
|
||||
http-check expect status 200
|
||||
mode tcp
|
||||
option ssl-hello-chk
|
||||
balance roundrobin
|
||||
{% for host in groups[kubernetes_control_plane_group] %}
|
||||
server {{ host }} {{ hostvars[host]['ansible_host'] }}:16443 check
|
||||
{% endfor %}
|
|
@ -0,0 +1,25 @@
|
|||
global_defs {
|
||||
router_id LVS_DEVEL
|
||||
}
|
||||
|
||||
vrrp_script check_apiserver {
|
||||
script "/etc/keepalived/check_apiserver.sh"
|
||||
interval 3
|
||||
weight -2
|
||||
fall 10
|
||||
rise 2
|
||||
}
|
||||
|
||||
vrrp_instance kubernetes {
|
||||
state MASTER
|
||||
interface {{ kubernetes_keepalived_interface }}
|
||||
virtual_router_id {{ kubernetes_keepalived_vrid }}
|
||||
|
||||
virtual_ipaddress {
|
||||
{{ kubernetes_keepalived_vip }}
|
||||
}
|
||||
|
||||
track_script {
|
||||
check_apiserver
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta3
|
||||
kind: InitConfiguration
|
||||
localAPIEndpoint:
|
||||
bindPort: 16443
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
cgroups-per-qos: "false"
|
||||
enforce-node-allocatable: ""
|
||||
node-ip: "{{ ansible_host }}"
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta3
|
||||
kind: JoinConfiguration
|
||||
nodeRegistration:
|
||||
kubeletExtraArgs:
|
||||
cgroups-per-qos: "false"
|
||||
enforce-node-allocatable: ""
|
||||
node-ip: "{{ ansible_host }}"
|
||||
{% if (_kubernetes_bootstrap_node is not defined) or (_kubernetes_bootstrap_node is defined and inventory_hostname != _kubernetes_bootstrap_node) %}
|
||||
discovery:
|
||||
bootstrapToken:
|
||||
token: "{{ _kubeadm_token_create.stdout | trim }}"
|
||||
apiServerEndpoint: "{{ kubernetes_hostname }}:6443"
|
||||
caCertHashes: ["sha256:{{ _kubeadm_certificate_info.public_key_fingerprints.sha256 | replace(':', '') }}"]
|
||||
{% if inventory_hostname in groups[kubernetes_control_plane_group] %}
|
||||
controlPlane:
|
||||
localAPIEndpoint:
|
||||
bindPort: 16443
|
||||
certificateKey: {{ _kubeadm_init_upload_certs.stdout | trim }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta3
|
||||
kind: ClusterConfiguration
|
||||
controlPlaneEndpoint: "{{ kubernetes_hostname }}:6443"
|
||||
apiServer:
|
||||
extraArgs:
|
||||
oidc-username-claim: email
|
||||
{% if kubernetes_oidc_issuer_url is defined %}
|
||||
oidc-issuer-url: {{ kubernetes_oidc_issuer_url }}
|
||||
oidc-client-id: {{ kubernetes_oidc_client_id }}
|
||||
{% endif %}
|
||||
controllerManager:
|
||||
extraArgs:
|
||||
bind-address: "0.0.0.0"
|
||||
scheduler:
|
||||
extraArgs:
|
||||
bind-address: "0.0.0.0"
|
||||
---
|
||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
---
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
kind: KubeProxyConfiguration
|
||||
metricsBindAddress: 0.0.0.0
|
|
@ -0,0 +1,3 @@
|
|||
{% for kubernetes_kernel_module in kubernetes_kernel_modules %}
|
||||
{{ kubernetes_kernel_module }}
|
||||
{% endfor %}
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
_kubernetes_upstream_apt_repository: https://apt.kubernetes.io/
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
[metadata]
|
||||
name = ansible-collection-atmosphere
|
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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 setuptools
|
||||
|
||||
setuptools.setup(pbr=True)
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
[tox]
|
||||
requires = tox-ansible
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
passenv =
|
||||
OS_*
|
||||
TERM
|
||||
STACK_NAME
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- job:
|
||||
name: ansible-collection-atmosphere-tox-molecule
|
||||
parent: vexxhost-tox-molecule
|
||||
pre-run:
|
||||
- zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/pre-run.yml
|
||||
vars:
|
||||
tox_environment:
|
||||
STACK_NAME: "atmosphere-{{ zuul.build }}"
|
||||
|
||||
- job:
|
||||
name: ansible-collection-atmosphere-tox-molecule-default
|
||||
parent: ansible-collection-atmosphere-tox-molecule
|
||||
vars:
|
||||
tox_envlist: default
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Create folder for Ansible collections
|
||||
file:
|
||||
path: "{{ ansible_user_dir }}/.ansible/collections/ansible_collections/vexxhost"
|
||||
state: directory
|
||||
|
||||
- name: Create symbloic link to Ansible collection
|
||||
file:
|
||||
src: "{{ ansible_user_dir }}/{{ zuul.project.src_dir }}"
|
||||
dest: "{{ ansible_user_dir }}/.ansible/collections/ansible_collections/vexxhost/atmosphere"
|
||||
state: link
|
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2022 VEXXHOST, 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.
|
||||
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- ansible-collection-atmosphere-tox-molecule-default
|
||||
gate:
|
||||
jobs:
|
||||
- ansible-collection-atmosphere-tox-molecule-default
|
Loading…
Reference in New Issue