From: Alex Ermolov Date: Sun, 14 Jun 2015 15:23:21 +0000 (+0300) Subject: Jenkins' job to deploy cluster VMs X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=880283a81c844a1334073fafb7b0fec091057578;p=tools%2Fsustaining.git Jenkins' job to deploy cluster VMs Also moved all jobs to separate dirs Change-Id: I424e59af5f02c71990e8c24a1e375d34f9da3356 --- diff --git a/jenkins/build_cluster.py b/jenkins/build_cluster/build_cluster.py similarity index 100% rename from jenkins/build_cluster.py rename to jenkins/build_cluster/build_cluster.py diff --git a/jenkins/config.xml b/jenkins/build_cluster/config.xml similarity index 100% rename from jenkins/config.xml rename to jenkins/build_cluster/config.xml diff --git a/jenkins/readme.txt b/jenkins/build_cluster/readme.txt similarity index 100% rename from jenkins/readme.txt rename to jenkins/build_cluster/readme.txt diff --git a/jenkins/scancodes.py b/jenkins/build_cluster/scancodes.py similarity index 100% rename from jenkins/scancodes.py rename to jenkins/build_cluster/scancodes.py diff --git a/jenkins/build_vm/contrib/instance_dd_test.sh b/jenkins/build_vm/contrib/instance_dd_test.sh new file mode 100644 index 0000000..b6716e8 --- /dev/null +++ b/jenkins/build_vm/contrib/instance_dd_test.sh @@ -0,0 +1,12 @@ +#!/bin/sh +time_seconds(){ (time -p $1 ) 2>&1 |awk '/real/{print $2}'; } +file=/tmp/test.img +c=100 #100M +write_seq=$(time_seconds "dd if=/dev/zero of=$file bs=1M count=$c") +read_seq=$(time_seconds "dd if=$file of=/dev/null bs=1M count=$c") +[ -f $file ] && rm $file + +echo "{ + \"write_seq\": $write_seq, + \"read_seq\": $read_seq + }" diff --git a/jenkins/build_vm/contrib/openrc b/jenkins/build_vm/contrib/openrc new file mode 100755 index 0000000..7a27633 --- /dev/null +++ b/jenkins/build_vm/contrib/openrc @@ -0,0 +1,14 @@ +#!/bin/sh +export LC_ALL=C +export OS_NO_CACHE='true' +export OS_TENANT_NAME='admin' +export OS_USERNAME='admin' +export OS_PASSWORD='admin' +export OS_AUTH_URL='http://192.168.0.2:5000/v2.0/' +export OS_AUTH_STRATEGY='keystone' +export OS_REGION_NAME='RegionOne' +export CINDER_ENDPOINT_TYPE='publicURL' +export GLANCE_ENDPOINT_TYPE='publicURL' +export KEYSTONE_ENDPOINT_TYPE='publicURL' +export NOVA_ENDPOINT_TYPE='publicURL' +export NEUTRON_ENDPOINT_TYPE='publicURL' diff --git a/jenkins/build_vm/contrib/rally-mos.yaml b/jenkins/build_vm/contrib/rally-mos.yaml new file mode 100644 index 0000000..f4f3473 --- /dev/null +++ b/jenkins/build_vm/contrib/rally-mos.yaml @@ -0,0 +1,510 @@ +--- + + KeystoneBasic.create_user: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_delete_user: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_and_list_tenants: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_and_list_users: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_tenant: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_tenant_with_users: + - + args: + name_length: 10 + users_per_tenant: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + sla: + failure_rate: + max: 0 + + KeystoneBasic.create_delete_user: + - + args: + name_length: 10 + runner: + type: "constant" + times: 1 + concurrency: 50 + sla: + failure_rate: + max: 0 + + HeatStacks.create_and_list_stack: + - + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + + HeatStacks.create_and_delete_stack: + - + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + + Authenticate.keystone: + - + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Authenticate.validate_cinder: + - + args: + repetitions: 2 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Authenticate.validate_glance: + - + args: + repetitions: 2 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Authenticate.validate_heat: + - + args: + repetitions: 2 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Authenticate.validate_nova: + - + args: + repetitions: 2 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Quotas.cinder_update_and_delete: + - + args: + max_quota: 1024 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Quotas.cinder_update: + - + args: + max_quota: 1024 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Quotas.nova_update_and_delete: + - + args: + max_quota: 1024 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + Quotas.nova_update: + - + args: + max_quota: 1024 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + VMTasks.boot_runcommand_delete: + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + floating_network: "net04_ext" + use_floatingip: true + script: "/home/tester/instance_dd_test.sh" + interpreter: "/bin/sh" + username: "cirros" + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: {} + sla: + failure_rate: + max: 0 + + + NovaServers.boot_and_delete_server: + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + - + args: + auto_assign_nic: true + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: + start_cidr: "10.2.0.0/24" + networks_per_tenant: 2 + sla: + failure_rate: + max: 0 + + + NovaServers.boot_and_list_server: + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + detailed: True + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + NovaServers.list_servers: + - + args: + detailed: True + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + servers: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + servers_per_tenant: 1 + sla: + failure_rate: + max: 0 + + NovaServers.boot_and_bounce_server: + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + actions: + - + hard_reboot: 1 + - + stop_start: 1 + - + rescue_unrescue: 1 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + NovaServers.boot_server: + - + args: + flavor: + name: "^ram64$" + image: + name: "TestVM|cirros.*uec" + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + flavors: + - + name: "ram64" + ram: 64 + sla: + failure_rate: + max: 0 + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + + HttpRequests.check_request: + - + args: + url: "http://www.example.com" + method: "GET" + status_code: 200 + runner: + type: "constant" + times: 2 + concurrency: 50 + sla: + failure_rate: + max: 0 + + NovaSecGroup.create_and_delete_secgroups: + - + args: + security_group_count: 5 + rules_per_security_group: 5 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + quotas: + nova: + security_groups: -1 + security_group_rules: -1 + sla: + failure_rate: + max: 0 + + NovaSecGroup.create_and_list_secgroups: + - + args: + security_group_count: 5 + rules_per_security_group: 5 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + quotas: + nova: + security_groups: -1 + security_group_rules: -1 + sla: + failure_rate: + max: 0 + + + NovaSecGroup.boot_and_delete_server_with_secgroups: + - + args: + flavor: + name: "m1.tiny" + image: + name: "TestVM|cirros.*uec" + security_group_count: 5 + rules_per_security_group: 5 + runner: + type: "constant" + times: 1 + concurrency: 50 + context: + users: + tenants: 1 + users_per_tenant: 1 + network: + start_cidr: "10.2.0.0/24" + quotas: + nova: + security_groups: -1 + security_group_rules: -1 diff --git a/jenkins/build_vm/testing-network_pub.xml b/jenkins/build_vm/testing-network_pub.xml new file mode 100644 index 0000000..11003ad --- /dev/null +++ b/jenkins/build_vm/testing-network_pub.xml @@ -0,0 +1,9 @@ + + testing-network_pub + + + + + + + diff --git a/jenkins/build_vm/vmutil.py b/jenkins/build_vm/vmutil.py new file mode 100755 index 0000000..f943c36 --- /dev/null +++ b/jenkins/build_vm/vmutil.py @@ -0,0 +1,761 @@ +#!/usr/bin/env python + +from argparse import ArgumentParser +from datetime import datetime +from functools import wraps +from inspect import getargspec +from time import mktime +import os +import subprocess +import sys +import time + +import libvirt +import paramiko + +cfg = dict() + +ISO_PATH = "/home/jenkins/workspace/deploy_cluster/iso/" +DEFAULT_DIST = "ubuntu" +DEFAULT_PUB_SUBNET = "testing-network_pub" +DEFAULT_AMD_SUBNET = "testing-network_adm" +LIBVIRT_IMAGES_PATH = "/var/lib/libvirt/images/" +VM_TEMPLATE_XML_PATH = "/home/jenkins/workspace/build_test_vm/" +VM_TEMPLATE_NAME = "template" +TEST_LOGIN = "tester" +TEST_PASSWORD = "test" + +iso_images = { + "ubuntu": ISO_PATH + "ubuntu-14.04.2-server-amd64.iso", + "centos": ISO_PATH + "CentOS-6.6-x86_64-minimal.iso" +} + +SYSPREP_OPS_ENABLED = [ + "abrt-data", + "bash-history", + "blkid-tab", + "crash-data", + "cron-spool", + "dhcp-client-state", + "dhcp-server-state", + "dovecot-data", + "logfiles", + "machine-id", + "mail-spool", + "net-hostname", + "net-hwaddr", + "pacct-log", + "package-manager-cache", + "pam-data", + "puppet-data-log", + "rh-subscription-manager", + "rhn-systemid", + "rpm-db", + "samba-db-log", + "script", + "smolt-uuid", + "ssh-userdir", + "sssd-db-log", + "tmp-files", + "udev-persistent-net", + "utmp", + "yum-uuid", + "customize", + "lvm-uuids"] + +APT_PACKAGES_PREINSTALL = [ + "vlan", + "git", + "build-essential", + "libssl-dev", + "libffi-dev", + "python-dev", + "libxml2-dev", + "libxslt1-dev", + "libpq-dev", + "python-pip" +] + +YUM_PACKAGES_PREINSTALL = [] + +NETWORK_SETUP_CMDS = [ + "sudo vconfig add eth1 101", + "sudo ifconfig eth1 up", + "sudo ifconfig eth1.101 inet 192.168.0.254/24 up", +] + +RALLY_CMDS = [ + "git clone https://github.com/openstack/rally rally-dist", + "~/rally-dist/install_rally.sh" +] + +TEMPEST_CMDS = [ + "git clone https://github.com/openstack/rally rally-dist", + "~/rally-dist/install_rally.sh" +] + +REMOTE_FAILURE_TOKENS_LIST = [ + "Failed", + "failed", + "Failure", + "HTTP 401" +] + + +try: + vconn = libvirt.open("qemu:///system") +except: + print ("\nERROR: libvirt is inaccessible!") + sys.exit(1) + + +def check_args(f): + @wraps(f) + def decorated(*args, **kwargs): + spec = getargspec(f) + none_args = [] + args_values = dict(zip(spec.args, args)) + for arg_name in args_values.keys(): + if not args_values[arg_name]: + none_args.append(arg_name) + if none_args: + for arg_name in none_args: + print "ERROR: {0} is not defined".format(arg_name) + print "exiting..." + exit(1) + return f(*args, **kwargs) + + return decorated + + +def make_now_timestr(): + return str(mktime( + datetime.now().timetuple())).split(".")[0] + + +def shell_cmd(cmdlist, stdin=None, stdout=None, stderr=subprocess.PIPE, + ignore_exceptions=False): + try: + proc = subprocess.Popen( + cmdlist, + stdin=stdin, + stdout=stdout, + stderr=stderr, + bufsize=1 + ) + proc.wait() + result = {} + if proc.returncode > 0: + message = "Error: " + proc.stderr.read() if proc.stderr \ + else "command returned {0}, something went wrong.".format( + proc.returncode) + raise Exception(message) + if stdin: + result["stdin"] = proc.stdin + if stdout: + result["stdout"] = proc.stdout + if stderr: + result["stderr"] = proc.stderr + except Exception as e: + if not ignore_exceptions: + raise e + return result + + +@check_args +def sftp_move(ip, login, password, filelist, remote_dir, local_dir, + upload=False): + paramiko.util.log_to_file("paramiko_sftp.log") + transport = paramiko.Transport((ip, 22)) + transport.connect(username=login, password=password) + sftp = paramiko.SFTPClient.from_transport(transport) + if upload: + for filename in filelist: + print "{0}/{2} --> {1}/{2}".format( + local_dir, remote_dir, filename) + sftp.put(local_dir + "/" + filename, remote_dir + "/" + filename) + else: + for filename in filelist: + sftp.get(remote_dir + "/" + filename, local_dir + "/" + filename) + sftp.close() + transport.close() + + +# FIXME: we assume NOPASSWD clause in destination's sudoers file +def perform_ssh_cmds(ip, login, password, cmds=None, filename=None, + sudo_password=None, echo_remote_output=False, + sleep=None, fail_on_errors=False): + if not cmds and not filename: + print("ERROR: Neither commands list nor file provided, aborting...") + sys.exit(1) + if filename: + with open(filename, "r") as fin: + content = fin.readlines() + cmds = content.split("\n") + paramiko.util.log_to_file("paramiko_ssh.log") + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(ip, + username=login, + password=password) + try: + for cmd in cmds: + if sleep: + time.sleep(sleep) + try: + stdin, stdout, stderr = client.exec_command(cmd) + result = stdout.read() + result_err = stderr.read() + if fail_on_errors: + for token in REMOTE_FAILURE_TOKENS_LIST: + if token in result_err: + raise Exception("Observed '{0}' in remote output, exiting.".format(token)) + print "sent command: {0}".format(cmd) + if echo_remote_output: + if result: + print "result:\n{0}".format(result) + if result_err: + print "stderr:\n{0}".format(result_err) + except Exception as e: + print e + sys.exit(1) + finally: + client.close() + + +def cleanup_vm(name, storage_pool="default", undefine=False): + try: + shell_cmd(["virsh", "destroy", name], ignore_exceptions=True) + if undefine: + shell_cmd(["virsh", "undefine", name], ignore_exceptions=True) + shell_cmd(["virsh", "vol-delete", "--pool", storage_pool, + name + ".img"], ignore_exceptions=True) + except Exception as e: + print e + sys.exit(1) + + +def show_vnc_console(name): + result = shell_cmd(["virsh", "domdisplay", name], + stdout=subprocess.PIPE) + print "{0}'s VNC console at: {1}".format( + name, + result["stdout"].read()) + + +def volume_create(name, disk_size, storage_pool): + vol_template = \ + "\n" \ + " {vol_name}.img\n" \ + " 0\n" \ + " {vol_size}\n" \ + " \n" \ + " \n" \ + " \n" \ + "\n" + try: + pool = vconn.storagePoolLookupByName(storage_pool) + except: + print("\nERROR: libvirt`s storage pool '{0}' is not accessible!" + .format(storage_pool)) + sys.exit(1) + + volume = vol_template.format(vol_name=name, + vol_size=disk_size) + + try: + vol_object = pool.createXML(volume) + except: + print("\nERROR: unable to create volume '{0}'!" + .format(name)) + sys.exit(1) + print("Created volume from XML:\n\n{0}".format(volume)) + return vol_object + + +@check_args +def create_vm(name, cpu_count, ram_amount, disk_size, storage_pool, + pub_subnet, iso_path): + vol_obj = volume_create(name, disk_size, storage_pool) + + node_template_xml = """ + + {name} + {memory} + {memory} + {vcpu} + + hvm + + + + + + + + + + + + + + + destroy + restart + destroy + + + + + + + {iso} + + +
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +