diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 000000000..96f8e876b --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,4 @@ +--- + +skip_list: + - '403' diff --git a/roles/python/.gitignore b/roles/python/.gitignore new file mode 100644 index 000000000..3827718ab --- /dev/null +++ b/roles/python/.gitignore @@ -0,0 +1 @@ +tox-py38 diff --git a/roles/python/Vagrantfile b/roles/python/Vagrantfile new file mode 100644 index 000000000..257cba349 --- /dev/null +++ b/roles/python/Vagrantfile @@ -0,0 +1,94 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +# Customize the count of CPU cores on the VM +CPUS = 4 + +# Customize the amount of memory on the VM +MEMORY = 8192 + +# Every Vagrant development environment requires a box. You can search for +# boxes at https://vagrantcloud.com/search. +BOX = "generic/centos7" + +HOSTNAME = "tobiko" + +TOX_INI_DIR = '../..' + + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + config.vm.box = BOX + config.vm.hostname = HOSTNAME + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # NOTE: This will enable public access to the opened port + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine and only allow access + # via 127.0.0.1 to disable public access + # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: DEVSTACK_HOST_IP + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network", ip: "172.18.161.6" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + + config.vm.provider "virtualbox" do |vb| + # Display the VirtualBox GUI when booting the machine + vb.gui = false + + vb.cpus = CPUS + vb.memory = MEMORY + end + + config.vm.provider "libvirt" do |libvirt| + libvirt.cpus = CPUS + libvirt.memory = MEMORY + end + + # No need to copy tox.ini folder to nodes to execute test cases + config.vm.synced_folder TOX_INI_DIR, "/vagrant", type: "rsync", + rsync__exclude: [".tox/"] + + config.vm.provision "ansible" do |ansible| + ansible.playbook = "resolv_conf.yaml" + end + + config.vm.provision "ansible" do |ansible| + ansible.playbook = "tox-py38.yaml" + end + +end diff --git a/roles/python/ansible.cfg b/roles/python/ansible.cfg new file mode 100644 index 000000000..e84f32523 --- /dev/null +++ b/roles/python/ansible.cfg @@ -0,0 +1,3 @@ +[default] +# human-readable stdout/stderr results display +stdout_callback = debug diff --git a/roles/python/defaults/main.yaml b/roles/python/defaults/main.yaml new file mode 100644 index 000000000..763f8382c --- /dev/null +++ b/roles/python/defaults/main.yaml @@ -0,0 +1,31 @@ +python_release: "3.8.0" +python_version: "3.8" +python_command: "python{{ python_version }}" +python_name: "Python-{{ python_release }}" +python_prefix: "/opt/{{ python_name }}" +python_executable: "{{ python_prefix }}/bin/{{ python_command }}" +python_url: "https://www.python.org/ftp/python/{{ python_release }}/{{ python_name }}.tgz" +python_tar: "{{ ansible_env.HOME }}/{{ python_url | basename }}" +python_src_dir: "{{ ansible_env.HOME }}/{{ python_name }}" + +pip_command: "pip{{ python_version }}" +pip_executable: "{{ python_prefix }}/bin/{{ pip_command }}" +pip_url: "https://bootstrap.pypa.io/get-pip.py" +pip_installer: "{{ ansible_env.HOME }}/{{ pip_url | basename }}" + +profile_file: "/etc/profile.d/{{ python_name }}.sh" +make_jobs: "{{ ansible_processor_vcpus }}" + +yum_install_packages: + - "@Development tools" + - zlib-devel + - openssl-devel + - bzip2-devel + - libffi-devel + +pip_install_base_packages: + - setuptools + - pip + - wheel + +pip_install_packages: [] diff --git a/roles/python/resolv_conf.yaml b/roles/python/resolv_conf.yaml new file mode 100644 index 000000000..c9925121c --- /dev/null +++ b/roles/python/resolv_conf.yaml @@ -0,0 +1,13 @@ +--- + +- hosts: all + tasks: + - name: Copy /etc/resolv.conf + become: yes + become_user: root + copy: + src: /etc/resolv.conf + dest: /etc/resolv.conf + owner: root + group: root + mode: '0644' diff --git a/roles/python/tasks/main.yaml b/roles/python/tasks/main.yaml new file mode 100644 index 000000000..a33466347 --- /dev/null +++ b/roles/python/tasks/main.yaml @@ -0,0 +1,105 @@ +--- + +- block: + - name: check '{{ python_executable }}' is installed + shell: | + '{{ python_executable }}' --version 2>&1 | \ + grep 'Python {{ python_version}}' + changed_when: false + + rescue: + - name: install '{{ python_name }}' build requeirements + become: yes + become_user: root + yum: + state: present + name: '{{ yum_install_packages }}' + when: "(yum_install_packages | length) > 0" + + - name: download '{{ python_name }}' from '{{ python_url }}' + get_url: + url: "{{ python_url }}" + dest: "{{ python_tar }}" + + - name: ensure '{{ python_src_dir | dirname }}' directory exists + file: + path: '{{ python_src_dir }}' + state: directory + + - name: extract '{{ python_tar | basename }}' into '{{ python_src_dir }}' + unarchive: + src: '{{ python_tar }}' + dest: '{{ python_src_dir | dirname }}' + remote_src: yes + + - name: configure '{{ python_name }}' + command: + cmd: './configure "--prefix={{ python_prefix }}"' + chdir: '{{ python_src_dir }}' + + - name: compile '{{ python_name }}' + command: + cmd: 'make -j {{ make_jobs }}' + chdir: '{{ python_src_dir }}' + + - name: install '{{ python_name }}' + become: yes + become_user: root + command: + cmd: 'make install' + chdir: '{{ python_src_dir }}' + + - name: check '{{ python_executable }}' is installed + shell: | + '{{ python_executable }}' --version 2>&1 | \ + grep 'Python {{ python_version}}' + changed_when: false + + +- block: + - name: check '{{ pip_executable }}' is installed + command: "'{{ pip_executable }}' --version" + changed_when: false + + rescue: + + + - name: download Pip installer from '{{ pip_url }}' + get_url: + url: "{{ pip_url }}" + dest: "{{ pip_installer }}" + + - name: "Install '{{ pip_executable }}'" + become: yes + become_user: root + command: "'{{ python_executable }}' '{{ pip_installer }}'" + + - name: check Pip is installed for '{{ pip_executable }}' + command: "'{{ pip_executable }}' --version" + changed_when: false + + +- name: "ensure base Python packages are installed and up-to-date" + become: true + become_user: root + pip: + executable: '{{ pip_executable }}' + state: latest + name: "{{ item }}" + vars: + ansible_python_interpreter: '{{ python_executable }}' + when: (item | length ) > 0 + loop: + - "{{ pip_install_base_packages }}" + - "{{ pip_install_packages }}" + + +- name: add '{{ profile_file }}' + become: yes + become_user: root + template: + src: profile.sh.j2 + dest: '{{ profile_file }}' + owner: root + group: root + mode: '0644' diff --git a/roles/python/templates/profile.sh.j2 b/roles/python/templates/profile.sh.j2 new file mode 100644 index 000000000..519137559 --- /dev/null +++ b/roles/python/templates/profile.sh.j2 @@ -0,0 +1 @@ +PATH={{ python_executable | dirname }}:$PATH diff --git a/roles/python/tox-py38.yaml b/roles/python/tox-py38.yaml new file mode 100644 index 000000000..e913ddb2c --- /dev/null +++ b/roles/python/tox-py38.yaml @@ -0,0 +1,42 @@ +--- + +- hosts: all + roles: + - role: . + vars: + python_version: "3.8" + python_release: "3.8.0" + pip_install_packages: + - virtualenv + - tox + + tasks: + - name: run test cases + shell: + cmd: tox -e py38 + chdir: /vagrant + register: run_test_cases + ignore_errors: true + + - name: produce test reports + shell: + cmd: tox -e report 2>&1 + chdir: /vagrant + + - name: get test reports + fetch: + src: "/vagrant/{{ item }}" + dest: "{{ playbook_dir }}/tox-py38/{{ inventory_hostname }}/{{ item }}" + flat: yes + loop: + - tobiko_results.html + + - name: check test cases result + assert: + that: run_test_cases.rc == 0 + fail_msg: | + Test cases failed + {{ run_test_cases.stdout }} + success_msg: | + Test cases passed + {{ run_test_cases.stdout }}