Add scripts to setup ONAP on OpenStack 73/50773/5
authorHarry Huang <huangxiangyu5@huawei.com>
Thu, 18 Jan 2018 12:43:47 +0000 (20:43 +0800)
committerHarry Huang <huangxiangyu5@huawei.com>
Wed, 7 Mar 2018 07:42:08 +0000 (15:42 +0800)
JIRA: Auto-5

Setup ONAP environment on OpenStack. Develop Using
Python considering its proved performence within
OPNFV testing project, and with its rich library we
can operate REST calls and json parsing in a more
elegant way, also others can reuse the existing
module to develop use cases and test cases.

Main workflow:
1. prepare OpenStack to launch ONAP (images, security
rules, keypair, etc)
2. launch ONAP stack

Change-Id: Id99affccbcaa86be134a535f89b26c54ad137e21
Signed-off-by: Harry Huang <huangxiangyu5@huawei.com>
14 files changed:
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
auto/__init__.py [new file with mode: 0644]
auto/util/__init__.py [new file with mode: 0644]
auto/util/openstack_lib.py [new file with mode: 0644]
auto/util/util.py [new file with mode: 0644]
auto/util/yaml_type.py [new file with mode: 0644]
prepare.sh [new file with mode: 0755]
requirements.txt [new file with mode: 0644]
setup.py [new file with mode: 0644]
setup/onap_on_openstack/__init__.py [new file with mode: 0644]
setup/onap_on_openstack/config.yml [new file with mode: 0644]
setup/onap_on_openstack/launch_onap.py [new file with mode: 0644]
setup/onap_on_openstack/onap_os_builder.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..bca7d11
--- /dev/null
@@ -0,0 +1,7 @@
+*.swp
+*.pyc
+/venv
+/work
+/auto.egg-info
+/build
+/dist
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..21e6bc9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,39 @@
+Auto
+====
+
+#### Recent Changes ####
+- Add util modules for common use in project
+- Add scripts to setup ONAP (Currently only on OpenStack)
+
+
+#### Current Code Structure ####
+
+    ├── auto # Auto modules
+    │   ├── __init__.py
+    │   └── util # util modules
+    │       ├── __init__.py
+    │       ├── openstack_lib.py
+    │       ├── util.py
+    │       └── yaml_type.py
+    ├── prepare.sh # prepare virtual env, install Auto modules
+    ├── requirements.txt
+    ├── setup # scripts to setup ONAP
+    │   └── onap_on_openstack # set ONAP on OpenStack using heat
+    │       ├── config.yml
+    │       ├── __init__.py
+    │       ├── launch_onap.py
+    │       └── onap_os_builder.py
+    └── setup.py # setup Auto modules
+
+#### Setup ONAP ####
+A working ONAP environment is required before other test activity aiming for ONAP can be carried out.
+
+**Usage**:
+
+1. run command:
+
+        bash prepare.sh
+2. configure setup/onap_on_openstack/config.yml
+3. under setup/onap_on_openstack/ run command:
+
+        python launch_onap.py -c config.yml
diff --git a/auto/__init__.py b/auto/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auto/util/__init__.py b/auto/util/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auto/util/openstack_lib.py b/auto/util/openstack_lib.py
new file mode 100644 (file)
index 0000000..4b62b72
--- /dev/null
@@ -0,0 +1,332 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+"""Module to manage OpenStack"""
+
+import os
+import re
+import sys
+import time
+import traceback
+
+from keystoneauth1 import loading
+from keystoneauth1 import session
+from keystoneclient import client as keystoneclient
+from glanceclient import client as glanceclient
+from neutronclient.neutron import client as neutronclient
+from novaclient import client as novaclient
+from heatclient import client as heatclient
+
+__author__ = "Harry Huang <huangxiangyu5@huawei.com>"
+
+DEFAULT_API_VERSION = '2'
+DEFAULT_ORCHESTRATION_API_VERSION = '1'
+
+openrc_base_key = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD']
+
+openrc_v3_exkey = ['OS_PROJECT_NAME',
+                   'OS_USER_DOMAIN_NAME',
+                   'OS_PROJECT_DOMAIN_NAME']
+
+openrc_v2_exkey = ['OS_TENANT_NAME']
+
+openrc_vars_mapping = {
+        'OS_USERNAME': 'username',
+        'OS_PASSWORD': 'password',
+        'OS_AUTH_URL': 'auth_url',
+        'OS_TENANT_NAME': 'tenant_name',
+        'OS_USER_DOMAIN_NAME': 'user_domain_name',
+        'OS_PROJECT_DOMAIN_NAME': 'project_domain_name',
+        'OS_PROJECT_NAME': 'project_name',
+    }
+
+
+def check_identity_api_version():
+    identity_api_version = os.getenv('OS_IDENTITY_API_VERSION')
+    auth_url = os.getenv('OS_AUTH_URL')
+    if not auth_url:
+        raise RuntimeError("Require env var: OS_AUTH_URL")
+    auth_url_parse = auth_url.split('/')
+    url_tail = auth_url_parse[-1] if auth_url_parse[-1] else auth_url_parse[-2]
+    url_identity_version = url_tail.strip('v')
+    if not identity_api_version and \
+           identity_api_version != url_identity_version:
+        raise RuntimeError("identity api version not consistent")
+    return url_identity_version
+
+
+def check_image_api_version():
+    image_api_version = os.getenv('OS_IMAGE_API_VERSION')
+    if image_api_version:
+        return image_api_version
+    else:
+        return DEFAULT_API_VERSION
+
+
+def check_network_api_version():
+    network_api_version = os.getenv('OS_NETWORK_API_VERSION')
+    if network_api_version:
+        return network_api_version
+    else:
+        return DEFAULT_API_VERSION
+
+
+def check_compute_api_version():
+    compute_api_version = os.getenv('OS_COMPUTE_API_VERSION')
+    if compute_api_version:
+        return compute_api_version
+    else:
+        return DEFAULT_API_VERSION
+
+
+def check_orchestration_api_version():
+    orchestration_api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
+    if orchestration_api_version:
+        return orchestration_api_version
+    else:
+        return DEFAULT_ORCHESTRATION_API_VERSION
+
+
+def get_project_name(creds):
+    identity_version = check_identity_api_version()
+    if identity_version == '3':
+        return creds["project_name"]
+    elif identity_version == '2':
+        return creds["tenant_name"]
+    else:
+        raise RuntimeError("Unsupported identity version")
+
+
+def get_credentials():
+    creds = {}
+    creds_env_key = openrc_base_key
+    identity_api_version = check_identity_api_version()
+
+    if identity_api_version == '3':
+        creds_env_key += openrc_v3_exkey
+    elif identity_api_version == '2':
+        creds_env_key += openrc_v2_exkey
+    else:
+        raise RuntimeError("Unsupported identity version")
+
+    for env_key in creds_env_key:
+        env_value = os.getenv(env_key)
+        if env_value is None:
+            raise RuntimeError("Require env var: %s" % env_key)
+        else:
+            creds_var = openrc_vars_mapping.get(env_key)
+            creds.update({creds_var: env_value})
+
+    return creds
+
+
+def get_session_auth(creds):
+    loader = loading.get_plugin_loader('password')
+    auth = loader.load_from_options(**creds)
+    return auth
+
+
+def get_session(creds):
+    auth = get_session_auth(creds)
+    cacert = os.getenv('OS_CACERT')
+    insecure = os.getenv('OS_INSECURE', '').lower() == 'true'
+    verify = cacert if cacert else not insecure
+    return session.Session(auth=auth, verify=verify)
+
+
+def get_keystone_client(creds):
+    identity_api_version = check_identity_api_version()
+    sess = get_session(creds)
+    return keystoneclient.Client(identity_api_version,
+                                 session=sess,
+                                 interface=os.getenv('OS_INTERFACE', 'admin'))
+
+
+def get_glance_client(creds):
+    image_api_version = check_image_api_version()
+    sess = get_session(creds)
+    return glanceclient.Client(image_api_version, session=sess)
+
+
+def get_neutron_client(creds):
+    network_api_version = check_network_api_version()
+    sess = get_session(creds)
+    return neutronclient.Client(network_api_version, session=sess)
+
+
+def get_nova_client(creds):
+    compute_api_version = check_compute_api_version()
+    sess = get_session(creds)
+    return novaclient.Client(compute_api_version, session=sess)
+
+
+def get_heat_client(creds):
+    orchestration_api_version = check_orchestration_api_version()
+    sess = get_session(creds)
+    return heatclient.Client(orchestration_api_version, session=sess)
+
+
+def get_domain_id(keystone_client, domain_name):
+    domains = keystone_client.domains.list()
+    domain_id = None
+    for domain in domains:
+        if domain.name == domain_name:
+            domain_id = domain.id
+            break
+    return domain_id
+
+
+def get_project_id(keystone_client, project_name):
+    identity_version = check_identity_api_version()
+    if identity_version == '3':
+        projects = keystone_client.projects.list()
+    elif identity_version == '2':
+        projects = keystone_client.tenants.list()
+    else:
+        raise RuntimeError("Unsupported identity version")
+    project_id = None
+    for project in projects:
+        if project.name == project_name:
+            project_id = project.id
+            break
+    return project_id
+
+
+def get_image_id(glance_client, image_name):
+    images = glance_client.images.list()
+    image_id = None
+    for image in images:
+        if image.name == image_name:
+            image_id = image.id
+            break
+    return image_id
+
+
+def get_network_id(neutron_client, network_name):
+    networks = neutron_client.list_networks()['networks']
+    network_id = None
+    for network in networks:
+        if network['name'] == network_name:
+            network_id = network['id']
+            break
+    return network_id
+
+
+def get_security_group_id(neutron_client, secgroup_name, project_id=None):
+    security_groups = neutron_client.list_security_groups()['security_groups']
+    secgroup_id = []
+    for security_group in security_groups:
+        if security_group['name'] == secgroup_name:
+            secgroup_id = security_group['id']
+            if security_group['project_id'] == project_id or project_id is None:
+                break
+    return secgroup_id
+
+
+def get_secgroup_rule_id(neutron_client, secgroup_id, json_body):
+    secgroup_rules = \
+        neutron_client.list_security_group_rules()['security_group_rules']
+    secgroup_rule_id = None
+    for secgroup_rule in secgroup_rules:
+        rule_match = True
+        for key, value in json_body['security_group_rule'].items():
+            rule_match = rule_match and (value == secgroup_rule[key])
+        if rule_match:
+            secgroup_rule_id = secgroup_rule['id']
+            break
+    return secgroup_rule_id
+
+
+def get_keypair_id(nova_client, keypair_name):
+    keypairs = nova_client.keypairs.list()
+    keypair_id = None
+    for keypair in keypairs:
+        if keypair.name == keypair_name:
+            keypair_id = keypair.id
+            break
+    return keypair_id
+
+
+def create_project(keystone_client, creds, project_name, project_desc):
+    project_id = get_project_id(keystone_client, project_name)
+    if project_id:
+        return project_id
+
+    identity_version = check_identity_api_version()
+
+    if identity_version == '3':
+        domain_name = creds["user_domain_name"]
+        domain_id = get_domain_id(keystone_client, domain_name)
+        project = keystone_client.projects.create(
+                    name=project_name,
+                    description=project_desc,
+                    domain=domain_id,
+                    enabled=True)
+    elif identity_version == '2':
+        project = keystone_client.tenants.create(project_name,
+                                                 project_desc,
+                                                 enabled=True)
+    else:
+        raise RuntimeError("Unsupported identity version")
+
+    return project.id
+
+
+def create_image(glance_client, image_name, image_path, disk_format="qcow2",
+                 container_format="bare", visibility="public"):
+    if not os.path.isfile(image_path):
+        raise RuntimeError("Image file not found: %s" % image_path)
+    image_id = get_image_id(glance_client, image_name)
+    if not image_id:
+        image = glance_client.images.create(name=image_name,
+                                            visibility=visibility,
+                                            disk_format=disk_format,
+                                            container_format=container_format)
+        image_id = image.id
+        with open(image_path) as image_data:
+            glance_client.images.upload(image_id, image_data)
+    return image_id
+
+
+def create_secgroup_rule(neutron_client, secgroup_id, protocol, direction,
+                         port_range_min=None, port_range_max=None):
+    json_body = {'security_group_rule': {'direction': direction,
+                                         'security_group_id': secgroup_id,
+                                         'protocol': protocol}}
+
+    if bool(port_range_min) != bool(port_range_max):
+        raise RuntimeError("Start or end of protocol range is empty: [ %s, %s ]"
+                            % (port_range_min, port_range_max))
+    elif port_range_min and port_range_max:
+        json_body['security_group_rule'].update({'port_range_min':
+                                                port_range_min})
+        json_body['security_group_rule'].update({'port_range_max':
+                                                         port_range_max})
+
+    secgroup_id = get_secgroup_rule_id(neutron_client, secgroup_id, json_body)
+    if not secgroup_id:
+        neutron_client.create_security_group_rule(json_body)
+    return secgroup_id
+
+
+def update_compute_quota(nova_client, project_id, quotas):
+    nova_client.quotas.update(project_id, **quotas)
+
+
+def create_keypair(nova_client, keypair_name, keypair_path):
+    keypair_id = get_keypair_id(nova_client, keypair_name)
+    if not keypair_id:
+        with open(os.path.expanduser(keypair_path), 'r') as public_key:
+            key_data = public_key.read().decode('utf-8')
+            keypair = nova_client.keypairs.create(name=keypair_name,
+                                                  public_key=key_data)
+        keypair_id = keypair.id
+    return keypair_id
+
diff --git a/auto/util/util.py b/auto/util/util.py
new file mode 100644 (file)
index 0000000..0033900
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+"""Utility Module"""
+
+import os
+import git
+import urllib
+import yaml
+import traceback
+from Crypto.PublicKey import RSA
+from yaml_type import literal_unicode
+
+__author__ = "Harry Huang <huangxiangyu5@huawei.com>"
+
+
+def folded_unicode_representer(dumper, data):
+    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='>')
+
+
+def literal_unicode_representer(dumper, data):
+    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='|')
+
+
+def unicode_representer(dumper, uni):
+    node = yaml.ScalarNode(tag=u'tag:yaml.org,2002:str', value=uni)
+    return node
+
+
+def mkdir(path):
+    path = path.strip()
+    path = path.rstrip("\\")
+    isExist = os.path.exists(path)
+    if not isExist:
+        os.makedirs(path)
+        return True
+    else:
+        return False
+
+
+def download(url, file_path):
+    if os.path.exists(file_path):
+        return False
+    else:
+        urllib.urlretrieve(url, file_path)
+        return True
+
+
+def git_clone(git_repo, git_branch, clone_path):
+    if not os.path.exists(clone_path):
+        git.Repo.clone_from(git_repo, clone_path, branch=git_branch)
+
+
+def read_file(file_path):
+    with open(os.path.expanduser(file_path)) as fd:
+        return fd.read()
+
+
+def read_yaml(yaml_path):
+    with open(os.path.expanduser(yaml_path)) as fd:
+        return yaml.safe_load(fd)
+
+
+def write_yaml(yaml_data, yaml_path, default_style=False):
+    yaml.add_representer(literal_unicode, literal_unicode_representer)
+    yaml.add_representer(unicode, unicode_representer)
+    with open(os.path.expanduser(yaml_path), 'w') as fd:
+        return yaml.dump(yaml_data, fd,
+                         default_flow_style=default_style)
+
+
+def create_keypair(prikey_path, pubkey_path, size=2048):
+    key = RSA.generate(size)
+    with open(os.path.expanduser(prikey_path), 'w') as prikey_file:
+        os.chmod(prikey_path, 0600)
+        prikey_file.write(key.exportKey('PEM'))
+    pubkey = key.publickey()
+    with open(os.path.expanduser(pubkey_path), 'w') as pubkey_file:
+        pubkey_file.write(pubkey.exportKey('OpenSSH'))
diff --git a/auto/util/yaml_type.py b/auto/util/yaml_type.py
new file mode 100644 (file)
index 0000000..352fc7d
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+class folded_unicode(unicode): pass
+class literal_unicode(unicode): pass
diff --git a/prepare.sh b/prepare.sh
new file mode 100755 (executable)
index 0000000..75e1108
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Run this script to setup Auto virtualenv and install Auto modules into
+# it.
+# Usage:
+#       bash prepare.sh
+########################################################################
+
+pip install virtualenv
+virtualenv venv
+source ./venv/bin/activate
+pip install setuptools
+AUTO_DIR=$(pwd)
+cat << EOF >> venv/bin/activate
+export AUTO_DIR=$AUTO_DIR
+EOF
+python setup.py install
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..8ef8db6
--- /dev/null
@@ -0,0 +1,8 @@
+GitPython
+pycrypto
+keystoneauth1>=3.1.0
+python-keystoneclient>=3.8.0
+python-glanceclient>=2.8.0
+python-neutronclient>=6.3.0
+python-novaclient>=9.0.0
+python-heatclient>=1.6.1
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..c7ec804
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+import os
+from setuptools import setup, find_packages
+
+__author__ = "Harry Huang <huangxiangyu5@huawei.com>"
+
+
+requirement_path = os.path.join(
+    os.path.dirname(__file__), 'requirements.txt')
+with open(requirement_path, 'r') as fd:
+    requirements = [line.strip() for line in fd if line != '\n']
+
+setup(
+    name="auto",
+    version='1.0.0',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=requirements
+)
diff --git a/setup/onap_on_openstack/__init__.py b/setup/onap_on_openstack/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/setup/onap_on_openstack/config.yml b/setup/onap_on_openstack/config.yml
new file mode 100644 (file)
index 0000000..88c5db1
--- /dev/null
@@ -0,0 +1,64 @@
+---
+
+onap_stack_name: onap
+
+onap_demo_git:
+  repo: https://gerrit.onap.org/r/demo
+  branch: amsterdam
+  heat_template: heat/ONAP/onap_openstack.yaml
+  heat_env: heat/ONAP/onap_openstack.env
+
+onap_vm_images:
+  ubuntu_1404_image:
+    name: Ubuntu_14.04_trusty
+    url: https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
+  ubuntu_1604_image:
+    name: Ubuntu_16.04_xenial
+    url: https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img
+  dcae_centos_7_image:
+    name: Centos_7
+    url: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1711.qcow2
+
+onap_secgroup_rules:
+  - protocol: tcp
+    direction: ingress
+    port_range_min: 1
+    port_range_max: 65535
+
+  - protocol: icmp
+    direction: ingress
+    port_range_min:
+    port_range_max:
+
+onap_quota:
+  instances: 100
+  cores: 100
+  ram: 204800
+
+onap_keypair:
+  name: onap_key
+  pubkey_path: ~/.ssh/id_rsa.pub
+
+onap_user_config:
+  public_net_name: ext-net
+  flavor_small: m1.small
+  flavor_medium: m1.medium
+  flavor_large: m1.large
+  flavor_xlarge: m1.xlarge
+  flavor_xxlarge: m1.xlarge
+  openstack_tenant_name: admin
+  openstack_username: admin
+  openstack_api_key: 49ef27251b38c5124378010e7be8758eb
+  horizon_url: https://192.168.22.222:80
+  keystone_url: https://192.168.22.222:5000
+  dns_list: ["8.8.8.8"]
+  external_dns: 8.8.8.8
+  dns_forwarder: 192.168.22.222
+  dnsaas_config_enabled: true
+  dnsaas_region: RegionOne
+  dnsaas_keystone_url: https://192.168.22.222:5000
+  dnsaas_tenant_name: service
+  dnsaas_username: designate
+  dnsaas_password: 853ff4c5315221ce5a042954eac38ea6692092a33c
+  dcae_keystone_url: https://192.168.22.222:5000
+  dcae_domain: dcaeg2.onap.org
diff --git a/setup/onap_on_openstack/launch_onap.py b/setup/onap_on_openstack/launch_onap.py
new file mode 100644 (file)
index 0000000..948adfc
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+"""Launch ONAP on OpenStack"""
+
+import argparse
+from onap_os_builder import ONAP_os_builder
+
+__author__ = "Harry Huang <huangxiangyu5@huawei.com>"
+
+
+def read_cli_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--config', '-c',
+                        dest = 'config',
+                        action = 'store',
+                        default = './config.yml',
+                        help = 'config file')
+    return parser.parse_args()
+
+
+if __name__ == '__main__':
+    args = read_cli_args()
+    config = args.config
+    onap_builder = ONAP_os_builder(config)
+    onap_builder.clone_demo_code()
+    onap_builder.create_onap_vm_images()
+    onap_builder.create_onap_secgroup_rules()
+    onap_builder.set_quota()
+    onap_builder.create_onap_key()
+    onap_builder.set_onap_stack_params()
+    onap_builder.create_onap_stack()
diff --git a/setup/onap_on_openstack/onap_os_builder.py b/setup/onap_on_openstack/onap_os_builder.py
new file mode 100644 (file)
index 0000000..b6c5608
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+########################################################################
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+########################################################################
+
+"""ONAP builder for OpenStack"""
+
+import os
+import sys
+
+import auto.util.openstack_lib as os_lib
+import auto.util.util as util
+from auto.util.yaml_type import literal_unicode
+
+__author__ = "Harry Huang <huangxiangyu5@huawei.com>"
+
+
+class ONAP_os_builder(object):
+    """Prepare the OpenStack environment and launch ONAP stack"""
+    def __init__(self, config_file):
+
+        self.config = util.read_yaml(config_file)
+        self.stack_name = self.config['onap_stack_name']
+        self.demo_git = self.config['onap_demo_git']
+        self.vm_images = self.config['onap_vm_images']
+        self.secgroup_rules = self.config['onap_secgroup_rules']
+        self.quota = self.config['onap_quota']
+        self.keypair = self.config['onap_keypair']
+        self.user_config = self.config['onap_user_config']
+
+        self.creds = os_lib.get_credentials()
+        self.keystone_client = os_lib.get_keystone_client(self.creds)
+        self.glance_client = os_lib.get_glance_client(self.creds)
+        self.neutron_client = os_lib.get_neutron_client(self.creds)
+        self.nova_client = os_lib.get_nova_client(self.creds)
+        self.heat_client = os_lib.get_heat_client(self.creds)
+
+        self.auto_dir = os.getenv('AUTO_DIR')
+        self.work_dir = os.path.join(self.auto_dir, "work")
+        self.demo_repo_dir = os.path.join(self.work_dir, "demo")
+        self.heat_template = os.path.join(self.demo_repo_dir,
+                                          self.demo_git['heat_template'])
+        self.heat_env = os.path.join(self.demo_repo_dir,
+                                     self.demo_git['heat_env'])
+        self.image_dir = os.path.join(self.work_dir, "images")
+        self.keypair_dir = os.path.join(self.work_dir, "keypair")
+        util.mkdir(self.work_dir)
+
+
+    def clone_demo_code(self):
+        util.git_clone(self.demo_git['repo'], self.demo_git['branch'],
+                       self.demo_repo_dir)
+
+
+    def prepare_images(self):
+        util.mkdir(self.image_dir)
+        for _, image_info in self.vm_images.items():
+            image_path = os.path.join(self.image_dir, image_info['name'])
+            util.download(image_info['url'], image_path)
+
+
+    def create_onap_vm_images(self):
+        self.prepare_images()
+        for _, image_info in self.vm_images.items():
+            image_path = os.path.join(self.image_dir, image_info['name'])
+            os_lib.create_image(self.glance_client,
+                                image_info['name'],
+                                image_path)
+
+
+    def create_onap_secgroup_rules(self):
+        project_name = os_lib.get_project_name(self.creds)
+        project_id = os_lib.get_project_id(self.keystone_client, project_name)
+        secgroup_id = os_lib.get_security_group_id(self.neutron_client,
+                                                   "default", project_id)
+        for secgroup_rule in self.secgroup_rules:
+            os_lib.create_secgroup_rule(self.neutron_client, secgroup_id,
+                                        secgroup_rule['protocol'],
+                                        secgroup_rule['direction'],
+                                        secgroup_rule['port_range_min'],
+                                        secgroup_rule['port_range_max'])
+
+
+    def set_quota(self):
+        project_name = os_lib.get_project_name(self.creds)
+        project_id = os_lib.get_project_id(self.keystone_client, project_name)
+        os_lib.update_compute_quota(self.nova_client, project_id, self.quota)
+
+
+    def create_onap_key(self):
+        os_lib.create_keypair(self.nova_client, self.keypair['name'],
+                              self.keypair['pubkey_path'])
+
+
+    def set_onap_stack_params(self):
+        stack_config = util.read_yaml(self.heat_env)['parameters']
+
+        user_config = self.user_config
+        user_config.update({'ubuntu_1404_image':
+                      self.vm_images['ubuntu_1404_image']['name']})
+        user_config.update({'ubuntu_1604_image':
+                      self.vm_images['ubuntu_1604_image']['name']})
+        user_config.update({'dcae_centos_7_image':
+                      self.vm_images['dcae_centos_7_image']['name']})
+
+        pubkey_data = util.read_file(self.keypair['pubkey_path']).strip('\n')
+        user_config.update({'key_name': self.keypair['name']})
+        user_config.update({'pub_key': literal_unicode(pubkey_data)})
+
+        util.mkdir(self.keypair_dir)
+        prikey_path = os.path.join(self.keypair_dir, 'private.key')
+        pubkey_path = os.path.join(self.keypair_dir, 'public.key')
+        if not os.path.isfile(prikey_path) or not os.path.isfile(pubkey_path):
+            util.create_keypair(prikey_path, pubkey_path)
+
+        dcae_prikey_data = util.read_file(prikey_path).strip('\n')
+        dcae_pubkey_data = util.read_file(pubkey_path).strip('\n')
+        user_config.update({'dcae_public_key':
+                            literal_unicode(dcae_prikey_data)})
+        user_config.update({'dcae_private_key':
+                            literal_unicode(dcae_pubkey_data)})
+
+        public_net_id = os_lib.get_network_id(
+            self.neutron_client,
+            user_config['public_net_name']
+        )
+        user_config.update({'public_net_id': public_net_id})
+        project_id = os_lib.get_project_id(
+            self.keystone_client,
+            user_config['openstack_tenant_name']
+        )
+        user_config.update({'openstack_tenant_id': project_id})
+
+        for key, value in user_config.items():
+            stack_config[key] = value
+        heat_env_data = {'parameters': stack_config}
+        util.write_yaml(heat_env_data, self.heat_env)
+
+
+    def create_onap_stack(self):
+        stack_args = {}
+        stack_args['stack_name'] = self.stack_name
+        stack_args['template'] = util.read_file(self.heat_template)
+        stack_args['parameters'] = util.read_yaml(self.heat_env)['parameters']
+        self.heat_client.stacks.create(**stack_args)
+