summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Konstanski <ckonstanski@pippiandcarlos.com>2017-10-26 15:16:59 -0600
committerCarlos Konstanski <ckonstanski@pippiandcarlos.com>2017-10-26 15:16:59 -0600
commit4a1c4e8c3e6ca4ffbcd9ef38f07a1527226d7430 (patch)
tree2ce07ca014433fd0349514b065595db48be94e8d
initial commit
-rw-r--r--.gitignore2
-rwxr-xr-xci-script.py114
-rw-r--r--libs/.gitignore1
-rw-r--r--libs/__init__.py1
-rw-r--r--libs/environment.py53
-rw-r--r--libs/glance.py38
-rw-r--r--libs/keystone.py39
7 files changed, 248 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..80fb99f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*~
+*swp
diff --git a/ci-script.py b/ci-script.py
new file mode 100755
index 0000000..0e8ef6a
--- /dev/null
+++ b/ci-script.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+from libs.environment import *
+from libs.glance import *
+from libs.keystone import *
+import argparse
+import glob
+import os
+import shlex
+import subprocess
+import sys
+import yaml
+
+
+def run_shell_command(cmd):
+ return subprocess.check_output(cmd, shell=True)
+
+
+def read_manifests():
+ manifests = {}
+ manifests_glob = "%s/manifests/*.yaml" % os.path.dirname(os.path.realpath(__file__))
+ for manifest_file in glob.glob(manifests_glob):
+ with open(manifest_file, "r") as myfile:
+ manifest = yaml.load(myfile.read())
+ if manifest["image_name"] in manifests:
+ raise Exception("Duplicate image name in manifests: %s" % manifest["image_name"])
+ manifests[manifest["image_name"]] = manifest
+ return manifests
+
+
+def check_image_tag_current(glance, manifest):
+ image = glance.find("%s.%s" % (manifest["image_name"], manifest["image_type"]))
+ return image and str(manifest["tag"]) in image.tags
+
+
+def create_image(manifest):
+ cmd = shlex.quote("disk-image-create %s -t %s -o /tmp/%s.%s 2>&1" % (manifest["elements"], manifest["image_type"], manifest["image_name"], manifest["image_type"]))
+ cmdparts = shlex.split(cmd)
+ env = manifest["extra_envs"] if "extra_envs" in manifest else None
+ p = subprocess.Popen(cmdparts, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
+ out, err = p.communicate()
+ if p.returncode != 0:
+ raise Exception("Error running diskimage-builder:\n%s\n%s" % (out, err))
+
+
+def main(args):
+ env = Environment(args.os_auth_url,
+ args.os_project_name,
+ args.os_region,
+ args.os_username,
+ args.os_password,
+ args.os_project_domain_name,
+ args.os_user_domain_name,
+ args.os_identity_api_version,
+ args.os_image_api_version,
+ args.elements_path)
+ manifests = read_manifests()
+ keystone = Keystone(env)
+ glance = Glance(keystone, endpoint_type="publicURL")
+ for image_name, manifest in manifests.items():
+ if not check_image_tag_current(glance, manifest):
+ create_image(manifest)
+ glance.upload("%s.%s" % (image_name, image_type),
+ manifest["image_type"],
+ "/tmp/%s.%s" % (manifest["image_name"], manifest["image_type"]),
+ manifest["tag"])
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Image Foundry CI Process")
+ parser.add_argument("--os-auth-url",
+ required=False,
+ default=os.environ.get("OS_AUTH_URL", None),
+ help="OpenStack openrc environment variable: OS_AUTH_URL")
+ parser.add_argument("--os-project-name",
+ required=False,
+ default=os.environ.get("OS_PROJECT_NAME", None),
+ help="OpenStack openrc environment variable: OS_PROJECT_NAME")
+ parser.add_argument("--os-region",
+ required=False,
+ default=os.environ.get("OS_REGION", None),
+ help="OpenStack openrc environment variable: OS_REGION")
+ parser.add_argument("--os-username",
+ required=False,
+ default=os.environ.get("OS_USERNAME", None),
+ help="OpenStack openrc environment variable: OS_USERNAME")
+ parser.add_argument("--os-password",
+ required=False,
+ default=os.environ.get("OS_PASSWORD", None),
+ help="OpenStack openrc environment variable: OS_PASSWORD")
+ parser.add_argument("--os-project-domain-name",
+ required=False,
+ default=os.environ.get("OS_PROJECT_DOMAIN_NAME", None),
+ help="OpenStack openrc environment variable: OS_PROJECT_DOMAIN_NAME")
+ parser.add_argument("--os-user-domain-name",
+ required=False,
+ default=os.environ.get("OS_USER_DOMAIN_NAME", None),
+ help="OpenStack openrc environment variable: OS_USER_DOMAIN_NAME")
+ parser.add_argument("--os-identity-api-version",
+ required=False,
+ default=os.environ.get("OS_IDENTITY_API_VERSION", None),
+ help="OpenStack openrc environment variable: OS_IDENTITY_API_VERSION")
+ parser.add_argument("--os-image-api-version",
+ required=False,
+ default=os.environ.get("OS_IMAGE_API_VERSION", None),
+ help="OpenStack openrc environment variable: OS_IMAGE_API_VERSION")
+ parser.add_argument("--elements-path",
+ required=False,
+ default=os.environ.get("ELEMENTS_PATH", None),
+ help="diskimage-builder environment variable: ELEMENTS_PATH")
+ args = parser.parse_args()
+ main(args)
+ sys.exit(0)
diff --git a/libs/.gitignore b/libs/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/libs/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/libs/__init__.py b/libs/__init__.py
new file mode 100644
index 0000000..609997c
--- /dev/null
+++ b/libs/__init__.py
@@ -0,0 +1 @@
+__all__ = ["environment", "keystone", "glance"]
diff --git a/libs/environment.py b/libs/environment.py
new file mode 100644
index 0000000..f78f3d1
--- /dev/null
+++ b/libs/environment.py
@@ -0,0 +1,53 @@
+import sys
+import os
+
+
+class Environment(object):
+ def __init__(self,
+ os_auth_url,
+ os_project_name,
+ os_region,
+ os_username,
+ os_password,
+ os_project_domain_name,
+ os_user_domain_name,
+ os_identity_api_version,
+ os_image_api_version,
+ elements_path,
+ extra_envs={}):
+ if os_auth_url is None or \
+ os_project_name is None or \
+ os_region is None or \
+ os_username is None or \
+ os_password is None or \
+ os_project_domain_name is None or \
+ os_user_domain_name is None or \
+ os_identity_api_version is None or \
+ os_image_api_version is None or \
+ elements_path is None:
+ print("All required environment arguments must have a value. You passed in:" + \
+ "\nos_auth_url = " + str(os_auth_url) + \
+ "\nos_project_name = " + str(os_project_name) + \
+ "\nos_region = " + str(os_region) + \
+ "\nos_username = " + str(os_username) + \
+ "\nos_password = " + str(os_password) + \
+ "\nos_project_domain_name = " + str(os_project_domain_name) + \
+ "\nos_user_domain_name = " + str(os_user_domain_name) + \
+ "\nos_identity_api_version = " + str(os_identity_api_version) + \
+ "\nos_image_api_version = " + str(os_image_api_version) + \
+ "\nelements_path = " + str(elements_path))
+ sys.exit(1)
+ else:
+ self.os_auth_url = os_auth_url
+ self.os_project_name = os_project_name
+ self.os_region = os_region
+ self.os_username = os_username
+ self.os_password = os_password
+ self.os_project_domain_name = os_project_domain_name
+ self.os_user_domain_name = os_user_domain_name
+ self.os_identity_api_version = os_identity_api_version
+ self.os_image_api_version = os_image_api_version
+ self.elements_path = elements_path
+ self.extra_envs = {}
+ for key, value in [(k, v) for (k, v) in extra_envs.items() if v]:
+ self.extra_envs[key] = value
diff --git a/libs/glance.py b/libs/glance.py
new file mode 100644
index 0000000..b2a5c8d
--- /dev/null
+++ b/libs/glance.py
@@ -0,0 +1,38 @@
+from __future__ import print_function
+import datetime
+import glanceclient
+import json
+import time
+import traceback
+
+
+class Glance(object):
+ def __init__(self, keystone, endpoint_type="publicURL"):
+ self.keystone = keystone
+ self.glance = glanceclient.Client(keystone.os_image_api_version,
+ endpoint=keystone.get_glance_url(endpoint_type=endpoint_type),
+ session=keystone.session)
+
+ def find(self, image_name):
+ for image in self.glance.images.list():
+ if image.name == image_name:
+ return image
+ return None
+
+ def delete(self, image_name):
+ image = self.find(image_name)
+ if image:
+ self.glance.images.delete(image.id)
+
+ def upload(self, image_name, image_type, file_path, tag):
+ self.delete(image_name)
+ image = self.glance.images.create(name=image_name)
+ if image.status != "queued":
+ raise Exception("Image did not enter queued state upon create.")
+ image = self.glance.images.update(image.id, disk_format=image_type)
+ image = self.glance.images.update(image.id, container_format="bare")
+ image = self.glance.images.update(image.id, visibility="private")
+ image = self.glance.images.update(image.id, tags=[str(tag)])
+ with open(file_path, "rb") as myfile:
+ self.glance.images.upload(image.id, myfile)
+ return image.id
diff --git a/libs/keystone.py b/libs/keystone.py
new file mode 100644
index 0000000..05c4d8c
--- /dev/null
+++ b/libs/keystone.py
@@ -0,0 +1,39 @@
+from keystoneauth1.identity import v3
+from keystoneauth1 import session
+from keystoneclient.v3 import client as keystoneclient
+
+
+class Project(object):
+ def __init__(self, name, uuid):
+ self.name = name
+ self.uuid = uuid
+
+
+class Keystone(object):
+ def __init__(self, env):
+ if env.os_identity_api_version != "3":
+ raise Exception("Keystone v3 is required. You are using version %s" % env.os_identity_api_version)
+ self.os_identity_api_version = env.os_identity_api_version
+ self.os_image_api_version = env.os_image_api_version
+ self.os_auth_url = env.os_auth_url.replace("v2.0", "v3")
+
+ auth = v3.Password(username=env.os_username,
+ password=env.os_password,
+ project_domain_name=env.os_project_domain_name,
+ user_domain_name=env.os_user_domain_name,
+ project_name=env.os_project_name,
+ auth_url=self.os_auth_url)
+ self.session = session.Session(auth=auth)
+ self.client = keystoneclient.Client(session=self.session,
+ region_name=env.os_region)
+
+ def get_projects(self):
+ return map(lambda x: Project(x.name, x.id),
+ [p for p in self.client.projects.list() if p.enabled])
+
+ def get_catalog_url(self, service_type=None, endpoint_type="publicURL"):
+ return self.session.get_endpoint(service_type=service_type,
+ endpoint_type=endpoint_type)
+
+ def get_glance_url(self, endpoint_type="publicURL"):
+ return self.get_catalog_url(service_type="image", endpoint_type=endpoint_type)