Add 'packer-image-create' job
- add packer-image-create.groovy to create images with packer
- add 'tcp_tests/templates/_packer/' with configs for 'foundation'
node
Change-Id: I23379bef389adad791df9343930095a57af3fb55
diff --git a/jobs/pipelines/packer-image-create.groovy b/jobs/pipelines/packer-image-create.groovy
new file mode 100644
index 0000000..94133a7
--- /dev/null
+++ b/jobs/pipelines/packer-image-create.groovy
@@ -0,0 +1,114 @@
+/**
+ *
+ * Deploy the product cluster using Jenkins master on CICD cluster
+ *
+ * Expected parameters:
+
+ * IMAGE_NAME Name of the resulting image in the Glance or in artifacts
+
+ * BUILD_CONFIG_DRIVE_PATH Relative path in tcp-qa to the directory with meta-data and user-data files
+ * BUILD_PACKER_CONFIG_PATH Relative path in tcp-qa to the file with packer config (packer.json)
+ * BASE_IMAGE_URL Base image to build a new image, in qcow2. For example, released ubuntu cloud image
+ * BASE_IMAGE_MD5 Base image MD5 checksum. Image will be re-downloaded if not match with the local image checksum
+
+ * PACKER_URL URL to the zip archive with packer binary, see https://releases.hashicorp.com/packer/
+ * PACKER_ZIP_MD5 MD5 of the zip archive with packer binary
+
+ * OS_AUTH_URL OpenStack keystone catalog URL
+ * OS_PROJECT_NAME OpenStack project (tenant) name
+ * OS_USER_DOMAIN_NAME OpenStack user domain name
+ * OS_CREDENTIALS OpenStack username and password credentials ID in Jenkins
+ * UPLOAD_IMAGE_TO_GLANCE If True: upload image to glance; if False: store as an artifact
+
+ * TCP_QA_REFS Reference to the tcp-qa change on review.gerrithub.io, like refs/changes/46/418546/41
+ */
+
+@Library('tcp-qa')_
+
+def common = new com.mirantis.mk.Common()
+def shared = new com.mirantis.system_qa.SharedPipeline()
+
+timeout(time: 6, unit: 'HOURS') {
+ node () {
+ try {
+
+ stage("Clean the environment and clone tcp-qa") {
+ deleteDir()
+ shared.run_cmd("""\
+ git clone https://github.com/Mirantis/tcp-qa.git ${WORKSPACE}
+ """)
+ shared.update_working_dir(false)
+ sh "mkdir ./tmp"
+ }
+
+ def packer_zipname = "/tmp/packer.zip"
+ def configdrive_isoname = "./tmp/config-drive.iso"
+
+ stage("Prepare Packer") {
+ // Check that the archive is already downloaded and has a correct checksum. Remove if not match
+ if (fileExists(packer_zipname)) {
+ sh(script: "bash -cex 'md5sum -c --status <(echo ${PACKER_ZIP_MD5} ${packer_zipname})' || rm -f ${packer_zipname}", returnStdout: true)
+ }
+ // If the file is missing or removed, then download it and check the checksum
+ if (!fileExists(packer_zipname)) {
+ sh(script: "wget --quiet -O ${packer_zipname} ${PACKER_URL}", returnStdout: true)
+ // Should fail the job if not match
+ sh(script: "bash -cex 'md5sum -c --status <(echo ${PACKER_ZIP_MD5} ${packer_zipname})'", returnStdout: true)
+ }
+ sh "unzip ${packer_zipname}"
+ }
+
+ stage("Build the cloudinit ISO") {
+ // Check that genisoimage is installed, or try to install it
+ sh "which genisoimage || sudo apt-get -y install genisoimage"
+ // Generate config-drive ISO
+ sh "mkisofs -o ${configdrive_isoname} -V cidata -r -J --quiet ${BUILD_CONFIG_DRIVE_PATH}"
+ }
+
+ stage("Build the image '${IMAGE_NAME}'") {
+ // Build the image
+ sh (script: """\
+ set -ex;
+ export PACKER_LOG=1;
+ export PACKER_CACHE_DIR='/tmp/packer_cache_${IMAGE_NAME}/';
+ mkdir -p \${PACKER_CACHE_DIR};
+ ./packer build -machine-readable -parallel=false -only='qemu' ${BUILD_PACKER_CONFIG_PATH};
+ """, returnStdout: true)
+ }
+
+
+ if (env.UPLOAD_IMAGE_TO_GLANCE) {
+
+ stage("Upload generated config drive ISO into volume on cfg01 node") {
+ withCredentials([
+ [$class : 'UsernamePasswordMultiBinding',
+ credentialsId : env.OS_CREDENTIALS,
+ passwordVariable: 'OS_PASSWORD',
+ usernameVariable: 'OS_USERNAME']
+ ]) {
+ env.OS_IDENTITY_API_VERSION = 3
+
+ def imagePath = "tmp/${IMAGE_NAME}/${IMAGE_NAME}.qcow2"
+ shared.run_cmd("""\
+ openstack --insecure image delete ${IMAGE_NAME} || true
+ sleep 3
+ openstack --insecure image create ${IMAGE_NAME} --file ${imagePath} --disk-format qcow2 --container-format bare
+ """)
+ }
+ }
+ } else {
+
+ stage("Archive artifacts") {
+ archiveArtifacts artifacts: "tmp/${IMAGE_NAME}/${IMAGE_NAME}.qcow2"
+ }
+ }
+
+ } catch (e) {
+ common.printMsg("Job is failed", "purple")
+ throw e
+ } finally {
+ // Remove the image after job is finished
+ sh "rm -f ./tmp/${IMAGE_NAME}.qcow2 || true"
+ } // try
+ } // node
+} // timeout
\ No newline at end of file
diff --git a/src/com/mirantis/system_qa/SharedPipeline.groovy b/src/com/mirantis/system_qa/SharedPipeline.groovy
index 5a78a9f..06ca19d 100644
--- a/src/com/mirantis/system_qa/SharedPipeline.groovy
+++ b/src/com/mirantis/system_qa/SharedPipeline.groovy
@@ -185,15 +185,18 @@
""")
}
-def update_working_dir() {
+def update_working_dir(Boolean updateRequirements=true) {
// Use to fetch a patchset from gerrit to the working dir
run_cmd("""\
if [ -n "$TCP_QA_REFS" ]; then
set -e
git fetch https://review.gerrithub.io/Mirantis/tcp-qa $TCP_QA_REFS && git checkout FETCH_HEAD || exit \$?
- fi
- pip install -r tcp_tests/requirements.txt
- """)
+ fi""")
+ if (updateRequirements) {
+ run_cmd("""\
+ pip install -r tcp_tests/requirements.txt
+ """)
+ }
}
def swarm_bootstrap_salt_cluster_devops() {
diff --git a/tcp_tests/templates/_packer/foundation/config-drive/meta-data b/tcp_tests/templates/_packer/foundation/config-drive/meta-data
new file mode 100644
index 0000000..b0c74c9
--- /dev/null
+++ b/tcp_tests/templates/_packer/foundation/config-drive/meta-data
@@ -0,0 +1 @@
+hostname: foundation
diff --git a/tcp_tests/templates/_packer/foundation/config-drive/user-data b/tcp_tests/templates/_packer/foundation/config-drive/user-data
new file mode 100644
index 0000000..1d68c57
--- /dev/null
+++ b/tcp_tests/templates/_packer/foundation/config-drive/user-data
@@ -0,0 +1,72 @@
+#cloud-config, see http://cloudinit.readthedocs.io/en/latest/topics/examples.html
+
+ssh_pwauth: True
+users:
+ - name: root
+ sudo: ALL=(ALL) NOPASSWD:ALL
+ shell: /bin/bash
+ - name: jenkins
+ sudo: ALL=(ALL) NOPASSWD:ALL
+ shell: /bin/bash
+ ssh_authorized_keys:
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFSxeuXh2sO4VYL8N2dlNFVyNcr2RvoH4MeDD/cV2HThfU4/BcH6IOOWXSDibIU279bWVKCL7QUp3mf0Vf7HPuyFuC12QM+l7MwT0jCYh5um3hmAvM6Ga0nkhJygHexe9/rLEYzZJkIjP9/IS/YXSv8rhHg484wQ6qkEuq15nyMqil8tbDQCq0XQ+AWEpNpIa4pUoKmFMsOP8lq10KZXIXsJyZxizadr6Bh4Lm9LWrk8YCw7qP3rmgWxK/s8qXQh1ISZe6ONfcmk6p03qbh4H3CwKyWzxmnIHQvE6PgN/O+PuAZj3PbR2mkkJjYX4jNPlxvj8uTStaVPhAwfR9Spdx jenkins@cz8133
+
+disable_root: false
+chpasswd:
+ list: |
+ root:r00tme
+ jenkins:qalab
+ expire: False
+
+output:
+ all: '| tee -a /var/log/cloud-init-output.log /dev/tty0'
+
+runcmd:
+ # Create swap
+ - fallocate -l 16G /swapfile
+ - chmod 600 /swapfile
+ - mkswap /swapfile
+ - swapon /swapfile
+ - echo "/swapfile none swap defaults 0 0" >> /etc/fstab
+
+ # Enable root access
+ - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin yes/' /etc/ssh/sshd_config
+ - service sshd restart
+
+write_files:
+ - path: /etc/default/grub.d/97-enable-grub-menu.cfg
+ content: |
+ GRUB_RECORDFAIL_TIMEOUT=30
+ GRUB_TIMEOUT=3
+ GRUB_TIMEOUT_STYLE=menu
+
+ - path: /etc/network/interfaces
+ content: |
+ auto ens3
+ iface ens3 inet dhcp
+
+ - path: /etc/bash_completion.d/fuel_devops30_activate
+ content: |
+ source /home/jenkins/fuel-devops30/bin/activate
+
+ - path: /etc/sysctl.d/99-fuel-devops.conf
+ content: |
+ net.bridge.bridge-nf-call-arptables = 0
+ net.bridge.bridge-nf-call-ip6tables = 0
+ net.bridge.bridge-nf-call-iptables = 0
+
+ - path: /etc/ssh/ssh_config
+ content: |
+ Host *
+ SendEnv LANG LC_*
+ HashKnownHosts yes
+ GSSAPIAuthentication yes
+ GSSAPIDelegateCredentials no
+ ServerAliveInterval 300
+ ServerAliveCountMax 10
+ StrictHostKeyChecking no
+ UserKnownHostsFile /dev/null
+
+ - path: /etc/sudoers.d/99-mirantis
+ content: |
+ %mirantis ALL=(ALL) NOPASSWD:ALL
diff --git a/tcp_tests/templates/_packer/foundation/packer.json b/tcp_tests/templates/_packer/foundation/packer.json
new file mode 100644
index 0000000..452fdef
--- /dev/null
+++ b/tcp_tests/templates/_packer/foundation/packer.json
@@ -0,0 +1,64 @@
+{
+ "variables": {
+ "vm_name": "{{ env `IMAGE_NAME` }}.qcow2",
+ "image_path": "tmp/{{ env `IMAGE_NAME` }}",
+ "base_image_url": "{{ env `BASE_IMAGE_URL` }}",
+ "base_image_md5": "{{ env `BASE_IMAGE_MD5` }}",
+ "base_image_path": "base_image.qcow2",
+ "ssh_username": "root",
+ "ssh_password": "r00tme",
+ "ssh_wait_timeout": "30m",
+ "disk_size": "51200",
+ "boot_wait": "120s"
+ },
+
+ "builders":
+ [
+ {
+ "type": "qemu",
+ "qemuargs": [
+ [ "-m", "1024M" ],
+ [ "-cdrom", "tmp/config-drive.iso" ],
+ ["-device", "virtio-net,netdev=user.0"],
+ ["-object","rng-random,id=objrng0,filename=/dev/urandom"],
+ ["-device", "virtio-rng-pci,rng=objrng0,id=rng0,bus=pci.0,addr=0x10" ]
+ ],
+ "vm_name": "{{ user `vm_name` }}",
+ "output_directory": "{{ user `image_path` }}",
+ "format": "qcow2",
+ "iso_url": "{{ user `base_image_url` }}",
+ "iso_checksum": "{{ user `base_image_md5` }}",
+ "iso_checksum_type": "md5",
+ "iso_target_path": "{{ user `base_image_path`}}",
+ "disk_image": true,
+ "disk_compression": true,
+ "accelerator": "kvm",
+ "disk_size": "{{ user `disk_size`}}",
+ "headless": true,
+ "ssh_username": "{{ user `ssh_username` }}",
+ "ssh_password": "{{ user `ssh_password` }}",
+ "ssh_wait_timeout": "{{ user `ssh_wait_timeout` }}",
+ "ssh_host_port_min": 7000,
+ "ssh_host_port_max": 7050,
+ "shutdown_command": "shutdown -P now",
+ "boot_wait": "{{ user `boot_wait` }}"
+ }
+ ],
+
+ "provisioners": [
+ {
+ "type": "shell",
+ "environment_vars": [
+ "DEBIAN_FRONTEND=noninteractive"
+ ],
+ "execute_command": "echo '{{ user `ssh_password` }}' | {{.Vars}} sudo -S -E bash -x '{{.Path}}'",
+ "scripts": [
+ "tcp_tests/templates/_packer/scripts/ubuntu_packets.sh",
+ "tcp_tests/templates/_packer/scripts/ubuntu_ldap.sh",
+ "tcp_tests/templates/_packer/scripts/jenkins_virtualenvs.sh",
+ "tcp_tests/templates/_packer/scripts/ubuntu_cleanup.sh",
+ "tcp_tests/templates/_packer/scripts/zerodisk.sh"
+ ]
+ }
+ ]
+}
diff --git a/tcp_tests/templates/_packer/scripts/jenkins_virtualenvs.sh b/tcp_tests/templates/_packer/scripts/jenkins_virtualenvs.sh
new file mode 100644
index 0000000..eb83ab4
--- /dev/null
+++ b/tcp_tests/templates/_packer/scripts/jenkins_virtualenvs.sh
@@ -0,0 +1,23 @@
+#!/bin/bash -xe
+
+DEVOPS_VENV_PATH=/home/jenkins/fuel-devops30
+REPORT_VENV_PATH=/home/jenkins/venv_testrail_reporter
+
+if [ ! -d ${DEVOPS_VENV_PATH} ]; then
+ virtualenv ${DEVOPS_VENV_PATH}
+fi
+if [ ! -d ${REPORT_VENV_PATH} ]; then
+ virtualenv ${REPORT_VENV_PATH}
+fi
+
+# Install tcp-qa requirements
+. ${DEVOPS_VENV_PATH}/bin/activate
+pip install -r https://raw.githubusercontent.com/Mirantis/tcp-qa/master/tcp_tests/requirements.txt
+pip install psycopg2 # workaround for setup with PostgreSQL , to keep requirements.txt for Sqlite3 only
+
+# Install xunit2testrail
+. ${REPORT_VENV_PATH}/bin/activate
+#pip install xunit2testrail -U
+pip install git+https://github.com/dis-xcom/testrail_reporter -U # Removed accessing to an unexisting pastebin on srv62
+
+chown -R jenkins:jenkins /home/jenkins/
diff --git a/tcp_tests/templates/_packer/scripts/ubuntu_cleanup.sh b/tcp_tests/templates/_packer/scripts/ubuntu_cleanup.sh
new file mode 100644
index 0000000..63a7586
--- /dev/null
+++ b/tcp_tests/templates/_packer/scripts/ubuntu_cleanup.sh
@@ -0,0 +1,70 @@
+#!/bin/bash -xe
+
+apt-get -y remove --purge unattended-upgrades || true
+apt-get -y autoremove --purge
+apt-get -y clean
+
+rm -rf /var/lib/apt/lists/* || true
+rm -rv /etc/apt/sources.list.d/* || true
+rm -rv /etc/apt/preferences.d/* || true
+echo > /etc/apt/sources.list || true
+rm -vf /usr/sbin/policy-rc.d || true
+
+echo "cleaning up hostname"
+sed -i "/.*ubuntu.*/d" /etc/hosts
+sed -i "/.*salt.*/d" /etc/hosts
+
+echo "cleaning up guest additions"
+rm -rf VBoxGuestAdditions_*.iso VBoxGuestAdditions_*.iso.? || true
+
+echo "cleaning up dhcp leases"
+rm -rf /var/lib/dhcp/* || true
+rm -rfv /var/lib/ntp/ntp.conf.dhcp || true
+
+echo "cleaning up udev rules"
+rm -fv /etc/udev/rules.d/70-persistent-net.rules || true
+rm -rf /dev/.udev/ || true
+rm -fv /lib/udev/rules.d/75-persistent-net-generator.rules || true
+
+echo "cleaning up minion_id for salt"
+rm -vf /etc/salt/minion_id || true
+
+echo "cleaning up resolvconf"
+sed -i '/172\.18\.208\.44/d' /etc/resolvconf/resolv.conf.d/base
+
+echo "cleaning up /var/cache/{apt,salt}/*"
+rm -rf /var/cache/{apt,salt}/* || true
+
+rm -rf /root/.cache || true
+rm -rf /root/.ssh/known_hosts || true
+
+# Remove flags
+rm -v /done_ubuntu_base || true
+rm -v /done_ubuntu_salt_bootstrap || true
+
+# Force cleanup cloud-init data, if it was
+if [[ -d '/var/lib/cloud/' ]] ; then
+ rm -rf /var/lib/cloud/* || true
+ cloud-init clean || true
+ echo > /var/log/cloud-init-output.log || true
+ echo > /var/log/cloud-init.log || true
+fi
+
+cat << EOF > /etc/network/interfaces
+# This file describes the network interfaces available on your system
+# and how to activate them. For more information, see interfaces(5).
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+# Source interfaces
+# Please check /etc/network/interfaces.d before changing this file
+# as interfaces may have been defined in /etc/network/interfaces.d
+# See LP: #1262951
+source /etc/network/interfaces.d/*.cfg
+EOF
+
+# Clear\drop cache's
+sync
+echo 3 > /proc/sys/vm/drop_caches
diff --git a/tcp_tests/templates/_packer/scripts/ubuntu_ldap.sh b/tcp_tests/templates/_packer/scripts/ubuntu_ldap.sh
new file mode 100644
index 0000000..4c400fb
--- /dev/null
+++ b/tcp_tests/templates/_packer/scripts/ubuntu_ldap.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -xe
+
+apt-get update
+apt-get install -y ldap-auth-client nscd ldap-utils
+
+auth-client-config -t nss -p lac_ldap
+
+sed -i 's$^#bind_policy hard$bind_policy soft$' /etc/ldap.conf
+sed -i 's$base dc=.*$base dc=mirantis,dc=net$' /etc/ldap.conf
+sed -i 's$uri ldap.*$uri ldap://ldap-bud.bud.mirantis.net/$' /etc/ldap.conf
+sed -i 's$^\(rootbinddn.*\)$#\1$' /etc/ldap.conf
+
+cat << 'EOF' >> /etc/ldap/ldap.conf
+BASE dc=mirantis,dc=net
+URI ldap://ldap-bud.bud.mirantis.net/
+EOF
+
+cat << 'EOF' > /usr/share/pam-configs/my_mkhomedir
+Name: activate mkhomedir
+Default: yes
+Priority: 900
+Session-Type: Additional
+Session:
+ required pam_mkhomedir.so umask=0022 skel=/etc/skel
+EOF
+
+cat << 'EOF' >> /etc/security/group.conf
+*;*;*;Al0000-2400;audio,cdrom,dialout,floppy,kvm,libvirtd
+EOF
+
+cat << 'EOF' > /usr/share/pam-configs/my_groups
+Name: activate /etc/security/group.conf
+Default: yes
+Priority: 900
+Auth-Type: Primary
+Auth:
+ required pam_group.so use_first_pass
+EOF
+
+cat << 'EOF' > /usr/local/sbin/ssh-ldap-keyauth
+#!/bin/bash
+
+/usr/bin/ldapsearch -x '(&(objectClass=posixAccount)(uid='"$1"'))' sshPublicKey | sed -n '/^ /{H;d};/sshPublicKey:/x;$g;s/\n *//g;s/sshPublicKey: //gp'
+EOF
+
+cat << 'EOF' >> /etc/ssh/sshd_config
+
+AuthorizedKeysCommand /usr/local/sbin/ssh-ldap-keyauth
+AuthorizedKeysCommandUser nobody
+EOF
+
+chmod +x /usr/local/sbin/ssh-ldap-keyauth
+DEBIAN_FRONTEND=noninteractive pam-auth-update
+
+#systemctl restart nscd.service;
+#systemctl restart sshd.service;
diff --git a/tcp_tests/templates/_packer/scripts/ubuntu_packets.sh b/tcp_tests/templates/_packer/scripts/ubuntu_packets.sh
new file mode 100644
index 0000000..883f620
--- /dev/null
+++ b/tcp_tests/templates/_packer/scripts/ubuntu_packets.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -xe
+
+apt-get update
+
+# for Jenkins agent
+apt-get install -y openjdk-8-jre-headless
+# for fuel-devops and tcp-qa
+apt-get install -y libyaml-dev libffi-dev libvirt-dev python-dev pkg-config vlan bridge-utils python-pip python3-pip virtualenv
+# additional tools
+apt-get install -y ebtables curl ethtool iputils-ping lsof strace tcpdump traceroute wget iptables htop \
+ git jq ntpdate tree mc byobu at pm-utils genisoimage iotop
+
+# ldap
+apt-get install -y ldap-auth-client nscd ldap-utils
+
+# update kernel
+apt-get install -y linux-generic-hwe-16.04
diff --git a/tcp_tests/templates/_packer/scripts/zerodisk.sh b/tcp_tests/templates/_packer/scripts/zerodisk.sh
new file mode 100644
index 0000000..159ae13
--- /dev/null
+++ b/tcp_tests/templates/_packer/scripts/zerodisk.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -x
+
+dd if=/dev/zero of=/EMPTY bs=1M || true
+rm -f /EMPTY
+
+sync
+echo 3 > /proc/sys/vm/drop_caches