diff --git a/ci/playbooks/devstack/post.yaml b/ci/playbooks/devstack/post.yaml new file mode 100644 index 00000000..e9eeeca4 --- /dev/null +++ b/ci/playbooks/devstack/post.yaml @@ -0,0 +1,3 @@ +- hosts: all + roles: + - fetch-tox-output diff --git a/ci/roles/auth/tasks/main.yml b/ci/roles/auth/tasks/main.yml new file mode 100644 index 00000000..c33a4aae --- /dev/null +++ b/ci/roles/auth/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: Authenticate to the cloud + openstack.cloud.os_auth: + cloud={{ cloud }} + +- debug: var=service_catalog diff --git a/ci/roles/client_config/tasks/main.yml b/ci/roles/client_config/tasks/main.yml new file mode 100644 index 00000000..9aeaf5cd --- /dev/null +++ b/ci/roles/client_config/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: List all profiles + openstack.cloud.os_client_config: + register: list + +# WARNING: This will output sensitive authentication information!!!! +- debug: var=list diff --git a/ci/roles/group/defaults/main.yml b/ci/roles/group/defaults/main.yml new file mode 100644 index 00000000..361c0119 --- /dev/null +++ b/ci/roles/group/defaults/main.yml @@ -0,0 +1 @@ +group_name: ansible_group diff --git a/ci/roles/group/tasks/main.yml b/ci/roles/group/tasks/main.yml new file mode 100644 index 00000000..2472856b --- /dev/null +++ b/ci/roles/group/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- name: Create group + openstack.cloud.os_group: + cloud: "{{ cloud }}" + state: present + name: "{{ group_name }}" + +- name: Update group + openstack.cloud.os_group: + cloud: "{{ cloud }}" + state: present + name: "{{ group_name }}" + description: "updated description" + +- name: Delete group + openstack.cloud.os_group: + cloud: "{{ cloud }}" + state: absent + name: "{{ group_name }}" diff --git a/ci/roles/image/defaults/main.yml b/ci/roles/image/defaults/main.yml new file mode 100644 index 00000000..13efe714 --- /dev/null +++ b/ci/roles/image/defaults/main.yml @@ -0,0 +1 @@ +image_name: ansible_image diff --git a/ci/roles/image/tasks/main.yml b/ci/roles/image/tasks/main.yml new file mode 100644 index 00000000..76937fd8 --- /dev/null +++ b/ci/roles/image/tasks/main.yml @@ -0,0 +1,54 @@ +--- +- name: Create a test image file + shell: mktemp + register: tmp_file + +- name: Fill test image file to 1MB + shell: truncate -s 1048576 {{ tmp_file.stdout }} + +- name: Create raw image (defaults) + openstack.cloud.os_image: + cloud: "{{ cloud }}" + state: present + name: "{{ image_name }}" + filename: "{{ tmp_file.stdout }}" + disk_format: raw + register: image + +- debug: var=image + +- name: Delete raw image (defaults) + openstack.cloud.os_image: + cloud: "{{ cloud }}" + state: absent + name: "{{ image_name }}" + +- name: Create raw image (complex) + openstack.cloud.os_image: + cloud: "{{ cloud }}" + state: present + name: "{{ image_name }}" + filename: "{{ tmp_file.stdout }}" + disk_format: raw + is_public: True + min_disk: 10 + min_ram: 1024 + kernel: cirros-vmlinuz + ramdisk: cirros-initrd + properties: + cpu_arch: x86_64 + distro: ubuntu + register: image + +- debug: var=image + +- name: Delete raw image (complex) + openstack.cloud.os_image: + cloud: "{{ cloud }}" + state: absent + name: "{{ image_name }}" + +- name: Delete test image file + file: + name: "{{ tmp_file.stdout }}" + state: absent diff --git a/ci/roles/keypair/defaults/main.yml b/ci/roles/keypair/defaults/main.yml new file mode 100644 index 00000000..3956b56a --- /dev/null +++ b/ci/roles/keypair/defaults/main.yml @@ -0,0 +1 @@ +keypair_name: shade_keypair diff --git a/ci/roles/keypair/tasks/main.yml b/ci/roles/keypair/tasks/main.yml new file mode 100644 index 00000000..7151a448 --- /dev/null +++ b/ci/roles/keypair/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: Create keypair (non-existing) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: present + register: + keypair + +# This assert verifies that Ansible is capable serializing data returned by SDK +- name: Ensure private key is returned + assert: + that: + - keypair.key.public_key is defined and keypair.key.public_key + +- name: Delete keypair (non-existing) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: absent + +- name: Generate test key file + user: + name: "{{ ansible_env.USER }}" + generate_ssh_key: yes + ssh_key_file: .ssh/shade_id_rsa + +- name: Create keypair (file) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: present + public_key_file: "{{ ansible_env.HOME }}/.ssh/shade_id_rsa.pub" + +- name: Delete keypair (file) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: absent + +- name: Create keypair (key) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: present + public_key: "{{ lookup('file', '~/.ssh/shade_id_rsa.pub') }}" + +- name: Delete keypair (key) + openstack.cloud.os_keypair: + cloud: "{{ cloud }}" + name: "{{ keypair_name }}" + state: absent + +- name: Delete test key pub file + file: + name: "{{ ansible_env.HOME }}/.ssh/shade_id_rsa.pub" + state: absent + +- name: Delete test key pvt file + file: + name: "{{ ansible_env.HOME }}/.ssh/shade_id_rsa" + state: absent diff --git a/ci/roles/keystone_domain/defaults/main.yml b/ci/roles/keystone_domain/defaults/main.yml new file mode 100644 index 00000000..049e7c37 --- /dev/null +++ b/ci/roles/keystone_domain/defaults/main.yml @@ -0,0 +1 @@ +domain_name: ansible_domain diff --git a/ci/roles/keystone_domain/tasks/main.yml b/ci/roles/keystone_domain/tasks/main.yml new file mode 100644 index 00000000..ef63605e --- /dev/null +++ b/ci/roles/keystone_domain/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- name: Create keystone domain + openstack.cloud.os_keystone_domain: + cloud: "{{ cloud }}" + state: present + name: "{{ domain_name }}" + description: "test description" + +- name: Update keystone domain + openstack.cloud.os_keystone_domain: + cloud: "{{ cloud }}" + name: "{{ domain_name }}" + description: "updated description" + +- name: Delete keystone domain + openstack.cloud.os_keystone_domain: + cloud: "{{ cloud }}" + state: absent + name: "{{ domain_name }}" diff --git a/ci/roles/keystone_role/defaults/main.yml b/ci/roles/keystone_role/defaults/main.yml new file mode 100644 index 00000000..d1ebe5d1 --- /dev/null +++ b/ci/roles/keystone_role/defaults/main.yml @@ -0,0 +1 @@ +role_name: ansible_keystone_role diff --git a/ci/roles/keystone_role/tasks/main.yml b/ci/roles/keystone_role/tasks/main.yml new file mode 100644 index 00000000..fc944210 --- /dev/null +++ b/ci/roles/keystone_role/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Create keystone role + openstack.cloud.os_keystone_role: + cloud: "{{ cloud }}" + state: present + name: "{{ role_name }}" + +- name: Delete keystone role + openstack.cloud.os_keystone_role: + cloud: "{{ cloud }}" + state: absent + name: "{{ role_name }}" diff --git a/ci/roles/network/defaults/main.yml b/ci/roles/network/defaults/main.yml new file mode 100644 index 00000000..d5435ecb --- /dev/null +++ b/ci/roles/network/defaults/main.yml @@ -0,0 +1,3 @@ +network_name: shade_network +network_shared: false +network_external: false diff --git a/ci/roles/network/tasks/main.yml b/ci/roles/network/tasks/main.yml new file mode 100644 index 00000000..215718b6 --- /dev/null +++ b/ci/roles/network/tasks/main.yml @@ -0,0 +1,14 @@ +--- +- name: Create network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + name: "{{ network_name }}" + state: present + shared: "{{ network_shared }}" + external: "{{ network_external }}" + +- name: Delete network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + name: "{{ network_name }}" + state: absent diff --git a/ci/roles/nova_flavor/tasks/main.yml b/ci/roles/nova_flavor/tasks/main.yml new file mode 100644 index 00000000..8fb70045 --- /dev/null +++ b/ci/roles/nova_flavor/tasks/main.yml @@ -0,0 +1,53 @@ +--- +- name: Create public flavor + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: present + name: ansible_public_flavor + is_public: True + ram: 1024 + vcpus: 1 + disk: 10 + ephemeral: 10 + swap: 1 + flavorid: 12345 + +- name: Delete public flavor + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: absent + name: ansible_public_flavor + +- name: Create private flavor + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: present + name: ansible_private_flavor + is_public: False + ram: 1024 + vcpus: 1 + disk: 10 + ephemeral: 10 + swap: 1 + flavorid: 12345 + +- name: Delete private flavor + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: absent + name: ansible_private_flavor + +- name: Create flavor (defaults) + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: present + name: ansible_defaults_flavor + ram: 1024 + vcpus: 1 + disk: 10 + +- name: Delete flavor (defaults) + openstack.cloud.os_nova_flavor: + cloud: "{{ cloud }}" + state: absent + name: ansible_defaults_flavor diff --git a/ci/roles/object/tasks/main.yml b/ci/roles/object/tasks/main.yml new file mode 100644 index 00000000..843225a1 --- /dev/null +++ b/ci/roles/object/tasks/main.yml @@ -0,0 +1,37 @@ +--- +- name: Create a test object file + shell: mktemp + register: tmp_file + +- name: Create container + openstack.cloud.os_object: + cloud: "{{ cloud }}" + state: present + container: ansible_container + container_access: private + +- name: Put object + openstack.cloud.os_object: + cloud: "{{ cloud }}" + state: present + name: ansible_object + filename: "{{ tmp_file.stdout }}" + container: ansible_container + +- name: Delete object + openstack.cloud.os_object: + cloud: "{{ cloud }}" + state: absent + name: ansible_object + container: ansible_container + +- name: Delete container + openstack.cloud.os_object: + cloud: "{{ cloud }}" + state: absent + container: ansible_container + +- name: Delete test object file + file: + name: "{{ tmp_file.stdout }}" + state: absent diff --git a/ci/roles/port/defaults/main.yml b/ci/roles/port/defaults/main.yml new file mode 100644 index 00000000..de022001 --- /dev/null +++ b/ci/roles/port/defaults/main.yml @@ -0,0 +1,6 @@ +network_name: ansible_port_network +network_external: true +subnet_name: ansible_port_subnet +port_name: ansible_port +secgroup_name: ansible_port_secgroup +no_security_groups: True diff --git a/ci/roles/port/tasks/main.yml b/ci/roles/port/tasks/main.yml new file mode 100644 index 00000000..24f8ed3d --- /dev/null +++ b/ci/roles/port/tasks/main.yml @@ -0,0 +1,101 @@ +--- +- name: Create network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: present + name: "{{ network_name }}" + external: "{{ network_external }}" + +- name: Create subnet + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: present + name: "{{ subnet_name }}" + network_name: "{{ network_name }}" + cidr: 10.5.5.0/24 + +- name: Create port (no security group or default security group) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: present + name: "{{ port_name }}" + network: "{{ network_name }}" + no_security_groups: "{{ no_security_groups }}" + fixed_ips: + - ip_address: 10.5.5.69 + register: port + +- debug: var=port + +- name: Delete port (no security group or default security group) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: absent + name: "{{ port_name }}" + +- name: Create security group + openstack.cloud.os_security_group: + cloud: "{{ cloud }}" + state: present + name: "{{ secgroup_name }}" + description: Test group + +- name: Create port (with security group) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: present + name: "{{ port_name }}" + network: "{{ network_name }}" + fixed_ips: + - ip_address: 10.5.5.69 + security_groups: + - "{{ secgroup_name }}" + register: port + +- debug: var=port + +- name: Delete port (with security group) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: absent + name: "{{ port_name }}" + +- name: Create port (with allowed_address_pairs and extra_dhcp_opts) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: present + name: "{{ port_name }}" + network: "{{ network_name }}" + no_security_groups: "{{ no_security_groups }}" + allowed_address_pairs: + - ip_address: 10.6.7.0/24 + extra_dhcp_opts: + - opt_name: "bootfile-name" + opt_value: "testfile.1" + register: port + +- debug: var=port + +- name: Delete port (with allowed_address_pairs and extra_dhcp_opts) + openstack.cloud.os_port: + cloud: "{{ cloud }}" + state: absent + name: "{{ port_name }}" + +- name: Delete security group + openstack.cloud.os_security_group: + cloud: "{{ cloud }}" + state: absent + name: "{{ secgroup_name }}" + +- name: Delete subnet + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: absent + name: "{{ subnet_name }}" + +- name: Delete network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: absent + name: "{{ network_name }}" diff --git a/ci/roles/router/defaults/main.yml b/ci/roles/router/defaults/main.yml new file mode 100644 index 00000000..f7d53933 --- /dev/null +++ b/ci/roles/router/defaults/main.yml @@ -0,0 +1,3 @@ +external_network_name: ansible_external_net +network_external: true +router_name: ansible_router diff --git a/ci/roles/router/tasks/main.yml b/ci/roles/router/tasks/main.yml new file mode 100644 index 00000000..e4f6d776 --- /dev/null +++ b/ci/roles/router/tasks/main.yml @@ -0,0 +1,95 @@ +--- +# Regular user operation +- name: Create internal network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: present + name: "{{ network_name }}" + external: false + +- name: Create subnet1 + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: present + network_name: "{{ network_name }}" + name: shade_subnet1 + cidr: 10.7.7.0/24 + +- name: Create router + openstack.cloud.os_router: + cloud: "{{ cloud }}" + state: present + name: "{{ router_name }}" + +- name: Update router (add interface) + openstack.cloud.os_router: + cloud: "{{ cloud }}" + state: present + name: "{{ router_name }}" + interfaces: + - shade_subnet1 + +# Admin operation +- name: Create external network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: present + name: "{{ external_network_name }}" + external: "{{ network_external }}" + when: + - network_external + +- name: Create subnet2 + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: present + network_name: "{{ external_network_name }}" + name: shade_subnet2 + cidr: 10.6.6.0/24 + when: + - network_external + +- name: Update router (add external gateway) + openstack.cloud.os_router: + cloud: "{{ cloud }}" + state: present + name: "{{ router_name }}" + network: "{{ external_network_name }}" + interfaces: + - shade_subnet1 + when: + - network_external + +- name: Delete router + openstack.cloud.os_router: + cloud: "{{ cloud }}" + state: absent + name: "{{ router_name }}" + +- name: Delete subnet1 + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: absent + name: shade_subnet1 + +- name: Delete subnet2 + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + state: absent + name: shade_subnet2 + when: + - network_external + +- name: Delete internal network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: absent + name: "{{ network_name }}" + +- name: Delete external network + openstack.cloud.os_network: + cloud: "{{ cloud }}" + state: absent + name: "{{ external_network_name }}" + when: + - network_external diff --git a/ci/roles/security_group/defaults/main.yml b/ci/roles/security_group/defaults/main.yml new file mode 100644 index 00000000..00310dd1 --- /dev/null +++ b/ci/roles/security_group/defaults/main.yml @@ -0,0 +1 @@ +secgroup_name: shade_secgroup diff --git a/ci/roles/security_group/tasks/main.yml b/ci/roles/security_group/tasks/main.yml new file mode 100644 index 00000000..7189afb0 --- /dev/null +++ b/ci/roles/security_group/tasks/main.yml @@ -0,0 +1,123 @@ +--- +- name: Create security group + openstack.cloud.os_security_group: + cloud: "{{ cloud }}" + name: "{{ secgroup_name }}" + state: present + description: Created from Ansible playbook + +- name: Create empty ICMP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: icmp + remote_ip_prefix: 0.0.0.0/0 + +- name: Create -1 ICMP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: icmp + port_range_min: -1 + port_range_max: -1 + remote_ip_prefix: 0.0.0.0/0 + +- name: Create empty TCP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: tcp + remote_ip_prefix: 0.0.0.0/0 + +- name: Create empty UDP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: udp + remote_ip_prefix: 0.0.0.0/0 + +- name: Create HTTP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: tcp + port_range_min: 80 + port_range_max: 80 + remote_ip_prefix: 0.0.0.0/0 + +- name: Create egress rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: present + protocol: tcp + port_range_min: 30000 + port_range_max: 30001 + remote_ip_prefix: 0.0.0.0/0 + direction: egress + +- name: Delete empty ICMP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: icmp + remote_ip_prefix: 0.0.0.0/0 + +- name: Delete -1 ICMP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: icmp + port_range_min: -1 + port_range_max: -1 + remote_ip_prefix: 0.0.0.0/0 + +- name: Delete empty TCP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: tcp + remote_ip_prefix: 0.0.0.0/0 + +- name: Delete empty UDP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: udp + remote_ip_prefix: 0.0.0.0/0 + +- name: Delete HTTP rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: tcp + port_range_min: 80 + port_range_max: 80 + remote_ip_prefix: 0.0.0.0/0 + +- name: Delete egress rule + openstack.cloud.os_security_group_rule: + cloud: "{{ cloud }}" + security_group: "{{ secgroup_name }}" + state: absent + protocol: tcp + port_range_min: 30000 + port_range_max: 30001 + remote_ip_prefix: 0.0.0.0/0 + direction: egress + +- name: Delete security group + openstack.cloud.os_security_group: + cloud: "{{ cloud }}" + name: "{{ secgroup_name }}" + state: absent diff --git a/ci/roles/server/defaults/main.yaml b/ci/roles/server/defaults/main.yaml new file mode 100644 index 00000000..e3bd5f33 --- /dev/null +++ b/ci/roles/server/defaults/main.yaml @@ -0,0 +1,5 @@ +server_network: private +server_name: ansible_server +flavor: m1.tiny +floating_ip_pool_name: public +boot_volume_size: 5 diff --git a/ci/roles/server/tasks/main.yml b/ci/roles/server/tasks/main.yml new file mode 100644 index 00000000..2fc2407d --- /dev/null +++ b/ci/roles/server/tasks/main.yml @@ -0,0 +1,92 @@ +--- +- name: Create server with meta as CSV + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: present + name: "{{ server_name }}" + image: "{{ image }}" + flavor: "{{ flavor }}" + network: "{{ server_network }}" + auto_floating_ip: false + meta: "key1=value1,key2=value2" + wait: true + register: server + +- debug: var=server + +- name: Delete server with meta as CSV + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: absent + name: "{{ server_name }}" + wait: true + +- name: Create server with meta as dict + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: present + name: "{{ server_name }}" + image: "{{ image }}" + flavor: "{{ flavor }}" + auto_floating_ip: false + network: "{{ server_network }}" + meta: + key1: value1 + key2: value2 + wait: true + register: server + +- debug: var=server + +- name: Delete server with meta as dict + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: absent + name: "{{ server_name }}" + wait: true + +- name: Create server (FIP from pool/network) + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: present + name: "{{ server_name }}" + image: "{{ image }}" + flavor: "{{ flavor }}" + network: "{{ server_network }}" + floating_ip_pools: + - "{{ floating_ip_pool_name }}" + wait: true + register: server + +- debug: var=server + +- name: Delete server (FIP from pool/network) + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: absent + name: "{{ server_name }}" + wait: true + +- name: Create server from volume + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: present + name: "{{ server_name }}" + image: "{{ image }}" + flavor: "{{ flavor }}" + network: "{{ server_network }}" + auto_floating_ip: false + boot_from_volume: true + volume_size: "{{ boot_volume_size }}" + terminate_volume: true + wait: true + register: server + +- debug: var=server + +- name: Delete server with volume + openstack.cloud.os_server: + cloud: "{{ cloud }}" + state: absent + name: "{{ server_name }}" + wait: true diff --git a/ci/roles/subnet/defaults/main.yml b/ci/roles/subnet/defaults/main.yml new file mode 100644 index 00000000..5ccc85ab --- /dev/null +++ b/ci/roles/subnet/defaults/main.yml @@ -0,0 +1,2 @@ +subnet_name: shade_subnet +enable_subnet_dhcp: false diff --git a/ci/roles/subnet/tasks/main.yml b/ci/roles/subnet/tasks/main.yml new file mode 100644 index 00000000..68445e8c --- /dev/null +++ b/ci/roles/subnet/tasks/main.yml @@ -0,0 +1,43 @@ +--- +- name: Create network {{ network_name }} + openstack.cloud.os_network: + cloud: "{{ cloud }}" + name: "{{ network_name }}" + state: present + +- name: Create subnet {{ subnet_name }} on network {{ network_name }} + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + network_name: "{{ network_name }}" + name: "{{ subnet_name }}" + state: present + enable_dhcp: "{{ enable_subnet_dhcp }}" + dns_nameservers: + - 8.8.8.7 + - 8.8.8.8 + cidr: 192.168.0.0/24 + gateway_ip: 192.168.0.1 + allocation_pool_start: 192.168.0.2 + allocation_pool_end: 192.168.0.254 + +- name: Update subnet + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + network_name: "{{ network_name }}" + name: "{{ subnet_name }}" + state: present + dns_nameservers: + - 8.8.8.7 + cidr: 192.168.0.0/24 + +- name: Delete subnet {{ subnet_name }} + openstack.cloud.os_subnet: + cloud: "{{ cloud }}" + name: "{{ subnet_name }}" + state: absent + +- name: Delete network {{ network_name }} + openstack.cloud.os_network: + cloud: "{{ cloud }}" + name: "{{ network_name }}" + state: absent diff --git a/ci/roles/user/tasks/main.yml b/ci/roles/user/tasks/main.yml new file mode 100644 index 00000000..cf1937c0 --- /dev/null +++ b/ci/roles/user/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: Create user + openstack.cloud.os_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret + email: ansible.user@nowhere.net + domain: default + default_project: demo + register: user + +- debug: var=user + +- name: Update user + openstack.cloud.os_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret + email: updated.ansible.user@nowhere.net + register: updateduser + +- debug: var=updateduser + +- name: Delete user + openstack.cloud.os_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user diff --git a/ci/roles/user_group/tasks/main.yml b/ci/roles/user_group/tasks/main.yml new file mode 100644 index 00000000..a42abad5 --- /dev/null +++ b/ci/roles/user_group/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Create user + openstack.cloud.os_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret + email: ansible.user@nowhere.net + domain: default + default_project: demo + register: user + +- name: Assign user to nonadmins group + openstack.cloud.os_user_group: + cloud: "{{ cloud }}" + state: present + user: ansible_user + group: nonadmins + +- name: Remove user from nonadmins group + openstack.cloud.os_user_group: + cloud: "{{ cloud }}" + state: absent + user: ansible_user + group: nonadmins + +- name: Delete user + openstack.cloud.os_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user diff --git a/ci/roles/volume/tasks/main.yml b/ci/roles/volume/tasks/main.yml new file mode 100644 index 00000000..cfa2f496 --- /dev/null +++ b/ci/roles/volume/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Create volume + openstack.cloud.os_volume: + cloud: "{{ cloud }}" + state: present + size: 1 + display_name: ansible_volume + display_description: Test volume + register: vol + +- debug: var=vol + +- name: Delete volume + openstack.cloud.os_volume: + cloud: "{{ cloud }}" + state: absent + display_name: ansible_volume diff --git a/ci/run-ansible-tests-collection.sh b/ci/run-ansible-tests-collection.sh new file mode 100755 index 00000000..54d6752b --- /dev/null +++ b/ci/run-ansible-tests-collection.sh @@ -0,0 +1,106 @@ +#!/bin/bash +############################################################################# +# run-ansible-tests.sh +# +# Script used to setup a tox environment for running Ansible. This is meant +# to be called by tox (via tox.ini). To run the Ansible tests, use: +# +# tox -e ansible [TAG ...] +# or +# tox -e ansible -- -c cloudX [TAG ...] +# or to use the development version of Ansible: +# tox -e ansible -- -d -c cloudX [TAG ...] +# +# USAGE: +# run-ansible-tests.sh -e ENVDIR [-d] [-c CLOUD] [TAG ...] +# +# PARAMETERS: +# -d Use Ansible source repo development branch. +# -e ENVDIR Directory of the tox environment to use for testing. +# -c CLOUD Name of the cloud to use for testing. +# Defaults to "devstack-admin". +# [TAG ...] Optional list of space-separated tags to control which +# modules are tested. +# +# EXAMPLES: +# # Run all Ansible tests +# run-ansible-tests.sh -e ansible +# +# # Run auth, keypair, and network tests against cloudX +# run-ansible-tests.sh -e ansible -c cloudX auth keypair network +############################################################################# +set -ex + +CLOUD="devstack-admin" +ENVDIR= +USE_DEV=0 + +while getopts "c:de:" opt +do + case $opt in + d) USE_DEV=1 ;; + c) CLOUD=${OPTARG} ;; + e) ENVDIR=${OPTARG} ;; + ?) echo "Invalid option: -${OPTARG}" + exit 1;; + esac +done + +if [ -z ${ENVDIR} ] +then + echo "Option -e is required" + exit 1 +fi + +shift $((OPTIND-1)) +TAGS=$( echo "$*" | tr ' ' , ) + +# We need to source the current tox environment so that Ansible will +# be setup for the correct python environment. +source $ENVDIR/bin/activate + +if [ ${USE_DEV} -eq 1 ] +then + if [ -d ${ENVDIR}/ansible ] + then + echo "Using existing Ansible source repo" + else + echo "Installing Ansible source repo at $ENVDIR" + git clone --recursive https://github.com/ansible/ansible.git ${ENVDIR}/ansible + fi + source $ENVDIR/ansible/hacking/env-setup +fi + +# Run the shade Ansible tests +tag_opt="" +if [ ! -z ${TAGS} ] +then + tag_opt="--tags ${TAGS}" +fi + +# Loop through all ANSIBLE_VAR_ environment variables to allow passing the further +for var in $(env | grep -e '^ANSIBLE_VAR_'); do + VAR_NAME=${var%%=*} # split variable name from value + ANSIBLE_VAR_NAME=${VAR_NAME#ANSIBLE_VAR_} # cut ANSIBLE_VAR_ prefix from variable name + ANSIBLE_VAR_NAME=${ANSIBLE_VAR_NAME,,} # lowercase ansible variable + ANSIBLE_VAR_VALUE=${!VAR_NAME} # Get the variable value + ANSIBLE_VARS+="${ANSIBLE_VAR_NAME}=${ANSIBLE_VAR_VALUE} " # concat variables +done + +# Until we have a module that lets us determine the image we want from +# within a playbook, we have to find the image here and pass it in. +# We use the openstack client instead of nova client since it can use clouds.yaml. +IMAGE=`openstack --os-cloud=${CLOUD} image list -f value -c Name | grep cirros | grep -v -e ramdisk -e kernel` +if [ $? -ne 0 ] +then + echo "Failed to find Cirros image" + exit 1 +fi + +# install collections +ansible-galaxy collection build --force . --output-path ./build_artifact +ansible-galaxy collection install $(ls build_artifact/openstack-cloud-*) --force +pushd ci/ +# run tests +ANSIBLE_COLLECTIONS_PATHS=${HOME}/.ansible/collections ansible-playbook -vvv ./run-collection.yml -e "cloud=${CLOUD} image=${IMAGE} ${ANSIBLE_VARS}" ${tag_opt} +popd diff --git a/ci/run-collection.yml b/ci/run-collection.yml new file mode 100644 index 00000000..9340ccd0 --- /dev/null +++ b/ci/run-collection.yml @@ -0,0 +1,26 @@ +--- +- hosts: localhost + connection: local + gather_facts: true + + roles: + - { role: auth, tags: auth } + - { role: client_config, tags: client_config } + - { role: group, tags: group } + # TODO(mordred) Reenable this once the fixed os_image winds up in an + # upstream ansible release. + # - { role: image, tags: image } + - { role: keypair, tags: keypair } + - { role: keystone_domain, tags: keystone_domain } + - { role: keystone_role, tags: keystone_role } + - { role: network, tags: network } + - { role: nova_flavor, tags: nova_flavor } + - { role: object, tags: object } + - { role: port, tags: port } + - { role: router, tags: router } + - { role: security_group, tags: security_group } + - { role: server, tags: server } + - { role: subnet, tags: subnet } + - { role: user, tags: user } + - { role: user_group, tags: user_group } + - { role: volume, tags: volume } diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 965d857c..a8884ae7 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -132,4 +132,5 @@ tests/unit/modules/cloud/openstack/test_os_server.py metaclass-boilerplate tests/unit/modules/conftest.py future-import-boilerplate tests/unit/modules/conftest.py metaclass-boilerplate tests/unit/modules/utils.py future-import-boilerplate -tests/unit/modules/utils.py metaclass-boilerplate \ No newline at end of file +tests/unit/modules/utils.py metaclass-boilerplate +ci/run-ansible-tests-collection.sh shebang diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index 5533b6f1..914cb75c 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -122,3 +122,4 @@ tests/unit/modules/conftest.py future-import-boilerplate tests/unit/modules/conftest.py metaclass-boilerplate tests/unit/modules/utils.py future-import-boilerplate tests/unit/modules/utils.py metaclass-boilerplate +ci/run-ansible-tests-collection.sh shebang diff --git a/tox.ini b/tox.ini index 0692391d..034c65d6 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,7 @@ setenv = OS_STDERR_CAPTURE={env:OS_STDERR_CAPTURE:true} deps = -r{toxinidir}/test-requirements.txt + commands = stestr run {posargs} stestr slowest @@ -47,3 +48,14 @@ commands = {posargs} ignore = W503,H4,E501,E402,H301,H236,F401,E128,W504,F841,F403,F405 show-source = True exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build + +[testenv:ansible-new] +# Need to pass some env vars for the Ansible playbooks +passenv = HOME USER ANSIBLE_VAR_* +deps = + {[testenv]deps} + {toxinidir}/../os-client-config + {toxinidir}/../openstacksdk + ansible +commands = + {toxinidir}/ci/run-ansible-tests-collection.sh -e {envdir} {posargs} diff --git a/zuul.yaml b/zuul.yaml index 9ccced27..96b57e2f 100644 --- a/zuul.yaml +++ b/zuul.yaml @@ -1,11 +1,71 @@ # yamllint disable --- +- job: + name: openstacksdk-functional-devstack-collections + parent: devstack-tox-functional + description: | + Minimum job for devstack-based functional tests + post-run: ci/playbooks/devstack/post.yaml + required-projects: + - openstack/os-client-config + - openstack/openstacksdk + timeout: 9000 + vars: + devstack_plugins: + neutron: https://opendev.org/openstack/neutron + #heat: https://opendev.org/openstack/heat + devstack_local_conf: + post-config: + $CINDER_CONF: + DEFAULT: + osapi_max_limit: 6 + devstack_localrc: + Q_ML2_PLUGIN_EXT_DRIVERS: qos,port_security + DISABLE_AMP_IMAGE_BUILD: true + Q_SERVICE_PLUGIN_CLASSES: qos,trunk + devstack_services: + # sdk doesn't need vnc access + n-cauth: false + n-novnc: false + # sdk testing uses config drive only + n-api-meta: false + q-meta: false + neutron-qos: true + neutron-trunk: true + neutron-port-forwarding: true + tox_environment: + # Do we really need to set this? It's cargo culted + PYTHONUNBUFFERED: 'true' + # Is there a way we can query the localconf variable to get these + # rather than setting them explicitly? + OPENSTACKSDK_HAS_DESIGNATE: 0 + OPENSTACKSDK_HAS_HEAT: 0 + OPENSTACKSDK_HAS_MAGNUM: 0 + OPENSTACKSDK_HAS_NEUTRON: 1 + OPENSTACKSDK_HAS_SWIFT: 1 + tox_install_siblings: false + tox_envlist: ansible + zuul_copy_output: + '{{ ansible_user_dir }}/ansible_logs': logs + zuul_work_dir: src/opendev.org/openstack/ansible-collections-openstack + +- job: + name: ansible-collections-openstack-functional-devstack + parent: openstacksdk-functional-devstack-collections + description: | + Run openstacksdk ansible functional tests against a master devstack + using Openstack collections + vars: + tox_envlist: ansible-new + - project: check: jobs: - tox-pep8 - openstack-tox-linters + - ansible-collections-openstack-functional-devstack gate: jobs: - tox-pep8 - openstack-tox-linters + - ansible-collections-openstack-functional-devstack