Try to move functional test to murano-tempest-plugin
Change-Id: I19debb3ca8cceb99d21a5bc500264b18e6bce8ce
This commit is contained in:
parent
3b4376e848
commit
139c835a2e
|
@ -0,0 +1,49 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import congressclient.v1.client as cclient
|
||||||
|
from keystoneauth1 import identity
|
||||||
|
from keystoneauth1 import session as ksasession
|
||||||
|
import keystoneclient.v3 as ksclient
|
||||||
|
from tempest import config
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as common_utils
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class TempestDeployTestMixin(common_utils.DeployTestMixin):
|
||||||
|
"""Overrides methods to use tempest configuration."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@common_utils.memoize
|
||||||
|
def keystone_client():
|
||||||
|
return ksclient.Client(username=CONF.auth.admin_username,
|
||||||
|
password=CONF.auth.admin_password,
|
||||||
|
tenant_name=CONF.auth.admin_project_name,
|
||||||
|
auth_url=CONF.identity.uri_v3)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@common_utils.memoize
|
||||||
|
def congress_client():
|
||||||
|
auth = identity.v3.Password(
|
||||||
|
auth_url=CONF.identity.uri_v3,
|
||||||
|
username=CONF.auth.admin_username,
|
||||||
|
password=CONF.auth.admin_password,
|
||||||
|
project_name=CONF.auth.admin_project_name,
|
||||||
|
user_domain_name=CONF.auth.admin_domain_name,
|
||||||
|
project_domain_name=CONF.auth.admin_domain_name)
|
||||||
|
session = ksasession.Session(auth=auth)
|
||||||
|
return cclient.Client(session=session,
|
||||||
|
service_type='policy')
|
|
@ -0,0 +1,553 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import contextlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import telnetlib
|
||||||
|
import time
|
||||||
|
|
||||||
|
from heatclient import client as heatclient
|
||||||
|
from keystoneclient import exceptions as ks_exceptions
|
||||||
|
import keystoneclient.v3 as ksclient
|
||||||
|
from muranoclient import client as mclient
|
||||||
|
import muranoclient.common.exceptions as exceptions
|
||||||
|
from muranoclient.glance import client as glare_client
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest import config
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.zip_utils_mixin \
|
||||||
|
as zip_utils
|
||||||
|
import murano_tempest_tests.tests.functional.engine.config as cfg
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
SessionState = collections.namedtuple('SessionState', [
|
||||||
|
'OPENED', 'DEPLOYING', 'DEPLOYED', 'DEPLOY_FAILURE', 'DELETING',
|
||||||
|
'DELETE_FAILURE'
|
||||||
|
])(
|
||||||
|
OPENED='opened',
|
||||||
|
DEPLOYING='deploying',
|
||||||
|
DEPLOYED='deployed',
|
||||||
|
DEPLOY_FAILURE='deploy failure',
|
||||||
|
DELETING='deleting',
|
||||||
|
DELETE_FAILURE='delete failure'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def ignored(*exceptions):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exceptions:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def memoize(f):
|
||||||
|
"""Saves result of decorated function to cache
|
||||||
|
|
||||||
|
Decorator, which saves result of a decorated function
|
||||||
|
to cache.
|
||||||
|
TTL for cache is 1800 sec
|
||||||
|
|
||||||
|
:param f: decorated function
|
||||||
|
:return: saved result of a decorated function
|
||||||
|
"""
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
def decorated_function(*args):
|
||||||
|
if args in cache:
|
||||||
|
if time.time() - cache[args][1] < 1800:
|
||||||
|
return cache[args][0]
|
||||||
|
else:
|
||||||
|
cache[args] = (f(*args), time.time())
|
||||||
|
return cache[args][0]
|
||||||
|
else:
|
||||||
|
cache[args] = (f(*args), time.time())
|
||||||
|
return cache[args][0]
|
||||||
|
|
||||||
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
|
class DeployTestMixin(zip_utils.ZipUtilsMixin):
|
||||||
|
|
||||||
|
# -----------------------------Clients methods---------------------------------
|
||||||
|
@staticmethod
|
||||||
|
@memoize
|
||||||
|
def keystone_client():
|
||||||
|
return ksclient.Client(username=CONF.auth.admin_username,
|
||||||
|
password=CONF.auth.admin_password,
|
||||||
|
tenant_name=CONF.auth.admin_project_name,
|
||||||
|
auth_url=CONF.identity.uri_v3)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@memoize
|
||||||
|
def heat_client(cls):
|
||||||
|
heat_url = cls.keystone_client().service_catalog.url_for(
|
||||||
|
service_type='orchestration', endpoint_type='publicURL')
|
||||||
|
return heatclient.Client('1',
|
||||||
|
endpoint=heat_url,
|
||||||
|
token=cls.keystone_client().auth_token)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@memoize
|
||||||
|
def murano_client(cls):
|
||||||
|
murano_url = cls.get_murano_url()
|
||||||
|
if CONF.murano.packages_service == "glare":
|
||||||
|
glare_endpoint = "http://127.0.0.1:9494"
|
||||||
|
artifacts_client = glare_client.Client(
|
||||||
|
endpoint=glare_endpoint,
|
||||||
|
token=cls.keystone_client().auth_token,
|
||||||
|
insecure=False, key_file=None, ca_file=None, cert_file=None,
|
||||||
|
type_name="murano", type_version=1)
|
||||||
|
else:
|
||||||
|
artifacts_client = None
|
||||||
|
return mclient.Client('1',
|
||||||
|
artifacts_client=artifacts_client,
|
||||||
|
endpoint=murano_url,
|
||||||
|
token=cls.keystone_client().auth_token)
|
||||||
|
|
||||||
|
# --------------------------Specific test methods------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deploy_apps(cls, name, *apps):
|
||||||
|
"""Create and deploy environment.
|
||||||
|
|
||||||
|
:param name: Murano environment name
|
||||||
|
:param apps: App(s), described in JSON format
|
||||||
|
:return: Murano environment
|
||||||
|
"""
|
||||||
|
environment = cls.murano_client().environments.create({'name': name})
|
||||||
|
cls.init_list("_environments")
|
||||||
|
cls._environments.append(environment)
|
||||||
|
session = cls.murano_client().sessions.configure(environment.id)
|
||||||
|
for app in apps:
|
||||||
|
cls.murano_client().services.post(
|
||||||
|
environment.id,
|
||||||
|
path='/',
|
||||||
|
data=app,
|
||||||
|
session_id=session.id)
|
||||||
|
cls.murano_client().sessions.deploy(environment.id, session.id)
|
||||||
|
return environment
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def wait_for_final_status(cls, environment, timeout=300):
|
||||||
|
"""Function for wait final status of environment.
|
||||||
|
|
||||||
|
:param environment: Murano environment.
|
||||||
|
:param timeout: Timeout for waiting environment to get any status
|
||||||
|
excluding DEPLOYING state
|
||||||
|
"""
|
||||||
|
start_time = time.time()
|
||||||
|
status = environment.manager.get(environment.id).status
|
||||||
|
while SessionState.DEPLOYING == status:
|
||||||
|
if time.time() - start_time > timeout:
|
||||||
|
err_msg = ('Deployment not finished in {amount} seconds'
|
||||||
|
.format(amount=timeout))
|
||||||
|
LOG.error(err_msg)
|
||||||
|
raise RuntimeError(err_msg)
|
||||||
|
time.sleep(5)
|
||||||
|
status = environment.manager.get(environment.id).status
|
||||||
|
dep = cls.murano_client().deployments.list(environment.id)
|
||||||
|
reports = cls.murano_client().deployments.reports(environment.id,
|
||||||
|
dep[0].id)
|
||||||
|
return status, ", ".join([r.text for r in reports])
|
||||||
|
|
||||||
|
# -----------------------------Reports methods---------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_last_deployment(cls, environment):
|
||||||
|
"""Gets last deployment of Murano environment.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
deployments = cls.murano_client().deployments.list(environment.id)
|
||||||
|
return deployments[0]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_deployment_report(cls, environment, deployment):
|
||||||
|
"""Gets reports for environment with specific deployment.
|
||||||
|
|
||||||
|
:param environment: Murano environment.
|
||||||
|
:param deployment: Murano deployment for certain environment
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
history = ''
|
||||||
|
report = cls.murano_client().deployments.reports(
|
||||||
|
environment.id, deployment.id)
|
||||||
|
for status in report:
|
||||||
|
history += '\t{0} - {1}\n'.format(status.created, status.text)
|
||||||
|
return history
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _log_report(cls, environment):
|
||||||
|
"""Used for logging reports on failures.
|
||||||
|
|
||||||
|
:param environment: Murano environment.
|
||||||
|
"""
|
||||||
|
deployment = cls.get_last_deployment(environment)
|
||||||
|
try:
|
||||||
|
details = deployment.result['result']['details']
|
||||||
|
LOG.warning('Details:\n {details}'.format(details=details))
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(e)
|
||||||
|
report = cls.get_deployment_report(environment, deployment)
|
||||||
|
LOG.debug('Report:\n {report}\n'.format(report=report))
|
||||||
|
|
||||||
|
# -----------------------------Service methods---------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_service(cls, environment, data, session, to_dict=False):
|
||||||
|
"""This function adds a specific service to environment.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param data: JSON with specific servive to add into
|
||||||
|
:param session: Session that is open for environment
|
||||||
|
:param to_dict: If True - returns a JSON object with service
|
||||||
|
If False - returns a specific class <Service>
|
||||||
|
"""
|
||||||
|
|
||||||
|
LOG.debug('Added service:\n {data}'.format(data=data))
|
||||||
|
service = cls.murano_client().services.post(environment.id,
|
||||||
|
path='/', data=data,
|
||||||
|
session_id=session.id)
|
||||||
|
if to_dict:
|
||||||
|
return cls._convert_service(service)
|
||||||
|
else:
|
||||||
|
return service
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def services_list(cls, environment):
|
||||||
|
"""Get a list of environment services.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:return: List of <Service> objects
|
||||||
|
"""
|
||||||
|
return cls.murano_client().services.list(environment.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_service(cls, environment, service_name, to_dict=True):
|
||||||
|
"""Get a service with specific name from environment.
|
||||||
|
|
||||||
|
:param to_dict: Convert service to JSON or not to convert
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param service_name: Service name
|
||||||
|
:return: JSON or <Service> object
|
||||||
|
"""
|
||||||
|
for service in cls.services_list(environment):
|
||||||
|
if service.name == service_name:
|
||||||
|
return cls._convert_service(service) if to_dict else service
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _convert_service(cls, service):
|
||||||
|
"""Converts a <Service> to JSON object.
|
||||||
|
|
||||||
|
:param service: <Service> object
|
||||||
|
:return: JSON object
|
||||||
|
"""
|
||||||
|
component = service.to_dict()
|
||||||
|
component = json.dumps(component)
|
||||||
|
return yaml.safe_load(component)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_service_id(cls, service):
|
||||||
|
"""Gets id on <Service> object.
|
||||||
|
|
||||||
|
:param service: <Service> object
|
||||||
|
:return: ID of the Service
|
||||||
|
"""
|
||||||
|
serv = cls._convert_service(service)
|
||||||
|
serv_id = serv['?']['id']
|
||||||
|
return serv_id
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete_service(cls, environment, session, service):
|
||||||
|
"""This function removes a specific service from environment.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param session: Session fir urano environment
|
||||||
|
:param service: <Service> object
|
||||||
|
:return: Updated murano environment
|
||||||
|
"""
|
||||||
|
cls.murano_client().services.delete(
|
||||||
|
environment.id, path='/{0}'.format(cls.get_service_id(service)),
|
||||||
|
session_id=session.id)
|
||||||
|
LOG.debug('Service with name {0} from environment {1} successfully '
|
||||||
|
'removed'.format(environment.name, service.name))
|
||||||
|
updated_env = cls.get_environment(environment)
|
||||||
|
return updated_env
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------Packages methods--------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def upload_package(cls, package_name, body, app):
|
||||||
|
"""Uploads a .zip package with parameters to Murano.
|
||||||
|
|
||||||
|
:param package_name: Package name in Murano repository
|
||||||
|
:param body: Categories, tags, etc.
|
||||||
|
e.g. {
|
||||||
|
"categories": ["Application Servers"],
|
||||||
|
"tags": ["tag"]
|
||||||
|
}
|
||||||
|
:param app: Correct .zip archive with the application
|
||||||
|
:return: Package
|
||||||
|
"""
|
||||||
|
files = {'{0}'.format(package_name): open(app, 'rb')}
|
||||||
|
package = cls.murano_client().packages.create(body, files)
|
||||||
|
cls.init_list("_packages")
|
||||||
|
cls._packages.append(package)
|
||||||
|
return package
|
||||||
|
|
||||||
|
# ------------------------------Common methods---------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def rand_name(cls, name='murano'):
|
||||||
|
"""Generates random string.
|
||||||
|
|
||||||
|
:param name: Basic name
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return name + str(random.randint(1, 0x7fffffff))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def init_list(cls, list_name):
|
||||||
|
if not hasattr(cls, list_name):
|
||||||
|
setattr(cls, list_name, [])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_murano_url(cls):
|
||||||
|
try:
|
||||||
|
url = cls.keystone_client().service_catalog.url_for(
|
||||||
|
service_type='application-catalog', endpoint_type='publicURL')
|
||||||
|
except ks_exceptions.EndpointNotFound:
|
||||||
|
url = CONF.murano.murano_url
|
||||||
|
LOG.warning("Murano endpoint not found in Keystone. "
|
||||||
|
"Using CONF.")
|
||||||
|
return url if 'v1' not in url else "/".join(
|
||||||
|
url.split('/')[:url.split('/').index('v1')])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def verify_connection(cls, ip, port):
|
||||||
|
"""Try to connect to specific ip:port with telnet.
|
||||||
|
|
||||||
|
:param ip: Ip that you want to check
|
||||||
|
:param port: Port that you want to check
|
||||||
|
:return: :raise RuntimeError:
|
||||||
|
"""
|
||||||
|
tn = telnetlib.Telnet(ip, port)
|
||||||
|
tn.write('GET / HTTP/1.0\n\n')
|
||||||
|
try:
|
||||||
|
buf = tn.read_all()
|
||||||
|
LOG.debug('Data:\n {data}'.format(data=buf))
|
||||||
|
if len(buf) != 0:
|
||||||
|
tn.sock.sendall(telnetlib.IAC + telnetlib.NOP)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Resource at {0}:{1} not exist'.
|
||||||
|
format(ip, port))
|
||||||
|
except socket.error as e:
|
||||||
|
LOG.error('Socket Error: {error}'.format(error=e))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_ip_by_appname(cls, environment, appname):
|
||||||
|
"""Returns ip of instance with a deployed application using app name.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param appname: Application name or substring of application name
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for service in environment.services:
|
||||||
|
if appname in service['name']:
|
||||||
|
return service['instance']['floatingIpAddress']
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_ip_by_instance_name(cls, environment, inst_name):
|
||||||
|
"""Returns ip of instance using instance name.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param name: String, which is substring of name of instance or name of
|
||||||
|
instance
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for service in environment.services:
|
||||||
|
if inst_name in service['instance']['name']:
|
||||||
|
return service['instance']['floatingIpAddress']
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_k8s_ip_by_instance_name(cls, environment, inst_name, service_name):
|
||||||
|
"""Returns ip of specific kubernetes node (gateway, master, minion).
|
||||||
|
|
||||||
|
Search depends on service name of kubernetes and names of spawned
|
||||||
|
instances
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param inst_name: Name of instance or substring of instance name
|
||||||
|
:param service_name: Name of Kube Cluster application in Murano
|
||||||
|
environment
|
||||||
|
:return: Ip of Kubernetes instances
|
||||||
|
"""
|
||||||
|
for service in environment.services:
|
||||||
|
if service_name in service['name']:
|
||||||
|
if "gateway" in inst_name:
|
||||||
|
for gateway in service['gatewayNodes']:
|
||||||
|
if inst_name in gateway['instance']['name']:
|
||||||
|
LOG.debug(gateway['instance']['floatingIpAddress'])
|
||||||
|
return gateway['instance']['floatingIpAddress']
|
||||||
|
elif "master" in inst_name:
|
||||||
|
LOG.debug(service['masterNode']['instance'][
|
||||||
|
'floatingIpAddress'])
|
||||||
|
return service['masterNode']['instance'][
|
||||||
|
'floatingIpAddress']
|
||||||
|
elif "minion" in inst_name:
|
||||||
|
for minion in service['minionNodes']:
|
||||||
|
if inst_name in minion['instance']['name']:
|
||||||
|
LOG.debug(minion['instance']['floatingIpAddress'])
|
||||||
|
return minion['instance']['floatingIpAddress']
|
||||||
|
|
||||||
|
# -----------------------------Cleanup methods---------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def purge_uploaded_packages(cls):
|
||||||
|
"""Cleanup for uploaded packages."""
|
||||||
|
cls.init_list("_packages")
|
||||||
|
try:
|
||||||
|
for pkg in cls._packages:
|
||||||
|
with ignored(Exception):
|
||||||
|
cls.murano_client().packages.delete(pkg.id)
|
||||||
|
finally:
|
||||||
|
cls._packages = []
|
||||||
|
cls.init_list("_package_files")
|
||||||
|
try:
|
||||||
|
for pkg_file in cls._package_files:
|
||||||
|
os.remove(pkg_file)
|
||||||
|
finally:
|
||||||
|
cls._package_files = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def purge_environments(cls):
|
||||||
|
"""Cleanup for created environments."""
|
||||||
|
cls.init_list("_environments")
|
||||||
|
try:
|
||||||
|
for env in cls._environments:
|
||||||
|
with ignored(Exception):
|
||||||
|
LOG.debug('Processing cleanup for environment {0} ({1})'.
|
||||||
|
format(env.name, env.id))
|
||||||
|
cls.environment_delete(env.id)
|
||||||
|
cls.purge_stacks(env.id)
|
||||||
|
time.sleep(5)
|
||||||
|
finally:
|
||||||
|
cls._environments = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def purge_stacks(cls, environment_id):
|
||||||
|
stack = cls._get_stack(environment_id)
|
||||||
|
if not stack:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
cls.heat_client().stacks.delete(stack.id)
|
||||||
|
|
||||||
|
# -----------------------Methods for environment CRUD--------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_environment(cls, name=None):
|
||||||
|
"""Creates Murano environment with random name.
|
||||||
|
|
||||||
|
|
||||||
|
:param name: Environment name
|
||||||
|
:return: Murano environment
|
||||||
|
"""
|
||||||
|
if not name:
|
||||||
|
name = cls.rand_name('MuranoTe')
|
||||||
|
environment = cls.murano_client().environments.create({'name': name})
|
||||||
|
cls._environments.append(environment)
|
||||||
|
return environment
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_environment(cls, environment):
|
||||||
|
"""Refresh <Environment> variable.
|
||||||
|
|
||||||
|
:param environment: Murano environment.
|
||||||
|
:return: Murano environment.
|
||||||
|
"""
|
||||||
|
return cls.murano_client().environments.get(environment.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def environment_delete(cls, environment_id, timeout=180):
|
||||||
|
"""Remove Murano environment.
|
||||||
|
|
||||||
|
:param environment_id: ID of Murano environment
|
||||||
|
:param timeout: Timeout to environment get deleted
|
||||||
|
:return: :raise RuntimeError:
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
cls.murano_client().environments.delete(environment_id)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
try:
|
||||||
|
cls.murano_client().environments.get(environment_id)
|
||||||
|
except exceptions.HTTPNotFound:
|
||||||
|
LOG.debug('Environment with id {0} successfully deleted.'.
|
||||||
|
format(environment_id))
|
||||||
|
return
|
||||||
|
err_msg = ('Environment {0} was not deleted in {1} seconds'.
|
||||||
|
format(environment_id, timeout))
|
||||||
|
LOG.error(err_msg)
|
||||||
|
raise RuntimeError(err_msg)
|
||||||
|
except Exception as exc:
|
||||||
|
LOG.debug('Environment with id {0} going to be abandoned.'.
|
||||||
|
format(environment_id))
|
||||||
|
LOG.exception(exc)
|
||||||
|
cls.murano_client().environments.delete(environment_id,
|
||||||
|
abandon=True)
|
||||||
|
|
||||||
|
# -----------------------Methods for session actions---------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_session(cls, environment):
|
||||||
|
return cls.murano_client().sessions.configure(environment.id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete_session(cls, environment, session):
|
||||||
|
return cls.murano_client().sessions.delete(environment.id, session.id)
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------Heat methods----------------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_stack(cls, environment_id):
|
||||||
|
|
||||||
|
for stack in cls.heat_client().stacks.list():
|
||||||
|
stack_description = (
|
||||||
|
cls.heat_client().stacks.get(stack.id).description)
|
||||||
|
if not stack_description:
|
||||||
|
err_msg = ("Stack {0} description is empty".format(stack.id))
|
||||||
|
LOG.error(err_msg)
|
||||||
|
raise RuntimeError(err_msg)
|
||||||
|
if environment_id in stack_description:
|
||||||
|
return stack
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_stack_template(cls, stack):
|
||||||
|
return cls.heat_client().stacks.template(stack.stack_name)
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
|
class ZipUtilsMixin(object):
|
||||||
|
@staticmethod
|
||||||
|
def zip_dir(parent_dir, dir):
|
||||||
|
abs_path = os.path.join(parent_dir, dir)
|
||||||
|
path_len = len(abs_path) + 1
|
||||||
|
zip_file = abs_path + ".zip"
|
||||||
|
with zipfile.ZipFile(zip_file, "w") as zf:
|
||||||
|
for dir_name, _, files in os.walk(abs_path):
|
||||||
|
for filename in files:
|
||||||
|
fn = os.path.join(dir_name, filename)
|
||||||
|
zf.write(fn, fn[path_len:])
|
||||||
|
return zip_file
|
|
@ -0,0 +1,45 @@
|
||||||
|
[murano]
|
||||||
|
# keystone url
|
||||||
|
# auth_url = http://127.0.0.1:5000/v2.0/
|
||||||
|
|
||||||
|
# keystone user
|
||||||
|
# user = admin
|
||||||
|
|
||||||
|
# password for keystone user
|
||||||
|
# password = admin
|
||||||
|
|
||||||
|
# keystone tenant
|
||||||
|
# tenant = admin
|
||||||
|
|
||||||
|
# keyname - used for debugging murano-agent
|
||||||
|
# keyname = keyname
|
||||||
|
|
||||||
|
# murano url
|
||||||
|
# murano_url = http://127.0.0.1:8082
|
||||||
|
|
||||||
|
# Flavor for sanity checks
|
||||||
|
# standard_flavor = m1.medium
|
||||||
|
|
||||||
|
# Flavor for advanced checks
|
||||||
|
# advanced_flavor = m1.medium
|
||||||
|
|
||||||
|
# image for linux services
|
||||||
|
# linux_image = default_linux
|
||||||
|
|
||||||
|
# murano instance type
|
||||||
|
# instance_type = io.murano.resources.LinuxMuranoInstance
|
||||||
|
|
||||||
|
# image for docker applications
|
||||||
|
# docker_image = debian-8-docker.qcow2
|
||||||
|
|
||||||
|
# image for kubernetes applications
|
||||||
|
# kubernetes_image = ubuntu14.04-x64-kubernetes.qcow2
|
||||||
|
|
||||||
|
# image for windows services
|
||||||
|
# windows_image = default_windows
|
||||||
|
|
||||||
|
# image for hdp sandbox
|
||||||
|
# hdp_image = hdp-sandbox
|
||||||
|
|
||||||
|
# region name for services
|
||||||
|
# region_name = None
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
murano_group = cfg.OptGroup(name='murano', title="murano")
|
||||||
|
|
||||||
|
MuranoGroup = [
|
||||||
|
cfg.StrOpt('auth_url',
|
||||||
|
default='http://127.0.0.1:5000',
|
||||||
|
help="keystone url"),
|
||||||
|
cfg.StrOpt('user',
|
||||||
|
default='admin',
|
||||||
|
help="keystone user"),
|
||||||
|
cfg.StrOpt('password',
|
||||||
|
default='pass',
|
||||||
|
help="password for keystone user"),
|
||||||
|
cfg.StrOpt('tenant',
|
||||||
|
default='admin',
|
||||||
|
help='keystone tenant'),
|
||||||
|
cfg.StrOpt('keyname',
|
||||||
|
default='',
|
||||||
|
help='name of keypair for debugging'),
|
||||||
|
cfg.StrOpt('murano_url',
|
||||||
|
default='http://127.0.0.1:8082/v1/',
|
||||||
|
help="murano url"),
|
||||||
|
cfg.StrOpt('standard_flavor',
|
||||||
|
default='m1.medium',
|
||||||
|
help="flavor for sanity tests"),
|
||||||
|
cfg.StrOpt('advanced_flavor',
|
||||||
|
default='m1.large',
|
||||||
|
help="flavor for advanced tests"),
|
||||||
|
cfg.StrOpt('linux_image',
|
||||||
|
default='default_linux',
|
||||||
|
help="image for linux services"),
|
||||||
|
cfg.StrOpt('instance_type',
|
||||||
|
default='io.murano.resources.LinuxMuranoInstance',
|
||||||
|
help="murano instance type"),
|
||||||
|
cfg.StrOpt('docker_image',
|
||||||
|
default='ubuntu14.04-x64-docker',
|
||||||
|
help="image for docker applications"),
|
||||||
|
cfg.StrOpt('windows_image',
|
||||||
|
default='default_windows',
|
||||||
|
help="image for windows services"),
|
||||||
|
cfg.StrOpt('hdp_image',
|
||||||
|
default="hdp-sandbox",
|
||||||
|
help="image for hdp-sandbox"),
|
||||||
|
cfg.StrOpt('kubernetes_image',
|
||||||
|
default="ubuntu14.04-x64-kubernetes",
|
||||||
|
help="image for kubernetes"),
|
||||||
|
cfg.StrOpt('region_name', help="region name for services"),
|
||||||
|
cfg.StrOpt('packages_service',
|
||||||
|
default='murano',
|
||||||
|
help='murano packages service, either "murano" or "glare"')
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
def register_config(config, config_group, config_opts):
|
||||||
|
|
||||||
|
config.register_group(config_group)
|
||||||
|
config.register_opts(config_opts, config_group)
|
||||||
|
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
__location = os.path.realpath(os.path.join(os.getcwd(),
|
||||||
|
os.path.dirname(__file__)))
|
||||||
|
path = os.path.join(__location, "config.conf")
|
||||||
|
|
||||||
|
if os.path.exists(path):
|
||||||
|
CONF([], project='muranointegration', default_config_files=[path])
|
||||||
|
|
||||||
|
register_config(CONF, murano_group, MuranoGroup)
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.apps.test
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
conf: io.murano.configuration
|
||||||
|
|
||||||
|
|
||||||
|
Name: ApacheHttpServerCustom
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
|
||||||
|
instance:
|
||||||
|
Contract: $.class(res:Instance).notNull()
|
||||||
|
|
||||||
|
userName:
|
||||||
|
Contract: $.string()
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Creating VM for Apache Server.')
|
||||||
|
- $securityGroupIngress:
|
||||||
|
- ToPort: 80
|
||||||
|
FromPort: 80
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- ToPort: 443
|
||||||
|
FromPort: 443
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
|
||||||
|
- $.instance.deploy()
|
||||||
|
- $._environment.reporter.report($this, 'Instance is created. Deploying Apache')
|
||||||
|
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
- $linux: new(conf:Linux)
|
||||||
|
|
||||||
|
- $linux.runCommand($.instance.agent, 'apt-get -y install apache2')
|
||||||
|
- $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT')
|
||||||
|
- $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT')
|
||||||
|
- $._environment.reporter.report($this, 'Apache is installed.')
|
||||||
|
|
||||||
|
- If: $.userName != ''
|
||||||
|
Then:
|
||||||
|
- $linux.runCommand($.instance.agent, 'service apache2 stop')
|
||||||
|
- $fileReplacements:
|
||||||
|
"%USER_NAME%": $.userName
|
||||||
|
- $fileContent: $resources.string('index.html').replace($fileReplacements)
|
||||||
|
- $linux.putFile($.instance.agent, $fileContent, '/var/www/html/index.html')
|
||||||
|
- $linux.runCommand($.instance.agent, 'service apache2 start')
|
||||||
|
|
||||||
|
- If: $.instance.assignFloatingIp
|
||||||
|
Then:
|
||||||
|
- $host: $.instance.floatingIpAddress
|
||||||
|
Else:
|
||||||
|
- $host: $.instance.ipAddresses[0]
|
||||||
|
- $._environment.reporter.report($this, format('Apache is available at http://{0}', $host))
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,175 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Hello World</title>
|
||||||
|
</head>
|
||||||
|
<body>Hello world. This is my first web page. My name is %USER_NAME%.
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.test.apache.ApacheHttpServerCustom
|
||||||
|
Name: Apache HTTP Server Custom
|
||||||
|
Description: |
|
||||||
|
The Apache HTTP Server Project is an effort to develop and maintain an
|
||||||
|
open-source HTTP server for modern operating systems including UNIX and
|
||||||
|
Windows NT. The goal of this project is to provide a secure, efficient and
|
||||||
|
extensible server that provides HTTP services in sync with the current HTTP
|
||||||
|
standards.
|
||||||
|
Apache httpd has been the most popular web server on the Internet since
|
||||||
|
April 1996, and celebrated its 17th birthday as a project this February.
|
||||||
|
Author: 'Mirantis, Inc'
|
||||||
|
Tags: [HTTP, Server, WebServer, HTML, Apache]
|
||||||
|
Classes:
|
||||||
|
io.murano.apps.test.ApacheHttpServerCustom: ApacheHttpServer.yaml
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.apps.test
|
||||||
|
std: io.murano
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
Name: Lighttpd
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
updater:
|
||||||
|
Contract: $.class(UpdateExecutor).notNull()
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $securityGroupIngress:
|
||||||
|
- ToPort: 80
|
||||||
|
FromPort: 80
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- ToPort: 443
|
||||||
|
FromPort: 443
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
|
||||||
|
- $._environment.reporter.report($this, 'Ensuring Updater is deployed.')
|
||||||
|
- $.updater.deploy()
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
- $template: $resources.yaml('DeployLighttpd.template')
|
||||||
|
- $.updater.instance.agent.call($template, $resources)
|
||||||
|
|
||||||
|
- If: $.updater.instance.assignFloatingIp
|
||||||
|
Then:
|
||||||
|
- $address: $.updater.instance.floatingIpAddress
|
||||||
|
- $._environment.reporter.report($this, format('Running at http://{0}', $address))
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,175 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
FormatVersion: 2.0.0
|
||||||
|
Version: 1.0.0
|
||||||
|
Name: Deploy Lighttpd
|
||||||
|
|
||||||
|
Body: |
|
||||||
|
deploy()
|
||||||
|
|
||||||
|
Scripts:
|
||||||
|
deploy:
|
||||||
|
Type: Application
|
||||||
|
Version: 1.0.0
|
||||||
|
EntryPoint: deployLighttpd.sh
|
||||||
|
Options:
|
||||||
|
captureStdout: true
|
||||||
|
captureStderr: true
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
sudo apt-get -y -q install lighttpd
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.apps.test.Lighttpd
|
||||||
|
Name: Lighttpd
|
||||||
|
Description: |
|
||||||
|
Lighttpd... :)
|
||||||
|
Author: 'Mirantis, Inc'
|
||||||
|
Tags: [Web]
|
||||||
|
Classes:
|
||||||
|
io.murano.apps.test.Lighttpd: Lighttpd.yaml
|
||||||
|
Require:
|
||||||
|
io.murano.apps.test.UpdateExecutor:
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.apps.test
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: UpdateExecutor
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
|
||||||
|
instance:
|
||||||
|
Contract: $.class(res:Instance).notNull()
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Creating VM.')
|
||||||
|
- $.instance.deploy()
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
- $template: $resources.yaml('Update.template')
|
||||||
|
- $._environment.reporter.report($this, 'Starting packages updating.')
|
||||||
|
- $.instance.agent.call($template, $resources)
|
||||||
|
- $._environment.reporter.report($this, 'Update completed.')
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,175 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
FormatVersion: 2.0.0
|
||||||
|
Version: 1.0.0
|
||||||
|
Name: Update
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
Body: |
|
||||||
|
update()
|
||||||
|
|
||||||
|
Scripts:
|
||||||
|
update:
|
||||||
|
Type: Application
|
||||||
|
Version: 1.0.0
|
||||||
|
EntryPoint: update.sh
|
||||||
|
Files: []
|
||||||
|
Options:
|
||||||
|
captureStdout: true
|
||||||
|
captureStderr: true
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
sudo apt-get update
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.apps.test.UpdateExecutor
|
||||||
|
Name: Update Executor
|
||||||
|
Description: |
|
||||||
|
Test application, which updates packages on VM
|
||||||
|
Author: 'Mirantis, Inc'
|
||||||
|
Tags: [application]
|
||||||
|
Classes:
|
||||||
|
io.murano.apps.test.UpdateExecutor: UpdateExecutor.yaml
|
|
@ -0,0 +1,48 @@
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.conflang.chef
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: ExampleChef
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
|
||||||
|
instance:
|
||||||
|
Contract: $.class(res:Instance).notNull()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Creating VM for Chef example ')
|
||||||
|
- $securityGroupIngress:
|
||||||
|
- ToPort: 22
|
||||||
|
FromPort: 22
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
|
||||||
|
- $.instance.deploy()
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
# Deploy Chef example
|
||||||
|
- $template: $resources.yaml('DeployExampleChef.template')
|
||||||
|
|
||||||
|
- $._environment.reporter.report($this, 'Instance is created. Deploying Chef example')
|
||||||
|
- $.instance.agent.call($template, $resources)
|
||||||
|
- If: $.instance.assignFloatingIp
|
||||||
|
Then:
|
||||||
|
- $host: $.instance.floatingIpAddress
|
||||||
|
Else:
|
||||||
|
- $host: $.instance.ipAddresses[0]
|
||||||
|
- $._environment.reporter.report($this, format('Chef example is installed at {0}', $host))
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,22 @@
|
||||||
|
FormatVersion: 2.1.0
|
||||||
|
Version: 1.0.0
|
||||||
|
Name: Deploy Example Chef
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
port: $port
|
||||||
|
|
||||||
|
Body: |
|
||||||
|
return executeRecipe(args).stdout
|
||||||
|
|
||||||
|
Scripts:
|
||||||
|
executeRecipe:
|
||||||
|
Type: Chef
|
||||||
|
Version: 1.0.0
|
||||||
|
EntryPoint: test::install
|
||||||
|
Files:
|
||||||
|
- test/recipes/install.rb
|
||||||
|
- test/metadata.rb
|
||||||
|
- test/README.rdoc
|
||||||
|
Options:
|
||||||
|
captureStdout: true
|
||||||
|
captureStderr: true
|
|
@ -0,0 +1,7 @@
|
||||||
|
= DESCRIPTION:
|
||||||
|
|
||||||
|
= REQUIREMENTS:
|
||||||
|
|
||||||
|
= ATTRIBUTES:
|
||||||
|
|
||||||
|
= USAGE:
|
|
@ -0,0 +1,8 @@
|
||||||
|
#comment
|
||||||
|
maintainer "Telefonica I+D"
|
||||||
|
maintainer_email "henar@tid.es"
|
||||||
|
name "test"
|
||||||
|
license "All rights reserved"
|
||||||
|
description "Default cookbook for testing"
|
||||||
|
long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
|
||||||
|
version "0.1.0"
|
|
@ -0,0 +1,10 @@
|
||||||
|
script "install" do
|
||||||
|
interpreter "bash"
|
||||||
|
user "root"
|
||||||
|
cwd "/opt"
|
||||||
|
code <<-EOH
|
||||||
|
echo test install
|
||||||
|
EOH
|
||||||
|
end
|
||||||
|
|
||||||
|
node.normal['test']['action_test'] = "install"
|
|
@ -0,0 +1,10 @@
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.conflang.chef.ExampleChef
|
||||||
|
Name: ExampleChef
|
||||||
|
Description: |
|
||||||
|
Example Chef.
|
||||||
|
Author: 'TID'
|
||||||
|
Tags: [Test, Chef]
|
||||||
|
Classes:
|
||||||
|
io.murano.conflang.chef.ExampleChef: ExampleChef.yaml
|
|
@ -0,0 +1,46 @@
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.conflang.puppet
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: ExamplePuppet
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
|
||||||
|
instance:
|
||||||
|
Contract: $.class(res:Instance).notNull()
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Creating VM for Example Chef example ')
|
||||||
|
- $securityGroupIngress:
|
||||||
|
- ToPort: 22
|
||||||
|
FromPort: 22
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
|
||||||
|
- $.instance.deploy()
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
# Deploy Puppet example
|
||||||
|
- $template: $resources.yaml('DeployExamplePuppet.template')
|
||||||
|
|
||||||
|
- $._environment.reporter.report($this, 'Instance is created. Deploying Example Puppet')
|
||||||
|
- $.instance.agent.call($template, $resources)
|
||||||
|
- If: $.instance.assignFloatingIp
|
||||||
|
Then:
|
||||||
|
- $host: $.instance.floatingIpAddress
|
||||||
|
Else:
|
||||||
|
- $host: $.instance.ipAddresses[0]
|
||||||
|
- $._environment.reporter.report($this, format('Example Puppet is installed at {0}', $host))
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,20 @@
|
||||||
|
FormatVersion: 2.1.0
|
||||||
|
Version: 1.0.0
|
||||||
|
Name: Deploy Example Puppet
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
port: $port
|
||||||
|
|
||||||
|
Body: |
|
||||||
|
return executeRecipe(args).stdout
|
||||||
|
|
||||||
|
Scripts:
|
||||||
|
executeRecipe:
|
||||||
|
Type: Puppet
|
||||||
|
Version: 1.0.0
|
||||||
|
EntryPoint: test::install
|
||||||
|
Files:
|
||||||
|
- test/manifests/install.pp
|
||||||
|
Options:
|
||||||
|
captureStdout: true
|
||||||
|
captureStderr: true
|
|
@ -0,0 +1,4 @@
|
||||||
|
class test::install($version='default_version'){
|
||||||
|
|
||||||
|
notify {"version: test":}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.conflang.puppet.ExamplePuppet
|
||||||
|
Name: ExamplePuppet
|
||||||
|
Description: |
|
||||||
|
Example Chef
|
||||||
|
Author: 'TID'
|
||||||
|
Tags: [Test, Puppet]
|
||||||
|
Classes:
|
||||||
|
io.murano.conflang.puppet.ExamplePuppet: ExamplePuppet.yaml
|
|
@ -0,0 +1,238 @@
|
||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
import requests
|
||||||
|
import testresources
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as utils
|
||||||
|
import murano_tempest_tests.tests.functional.engine.config as cfg
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.cfg.CONF
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MuranoTestsCore(testtools.TestCase, testtools.testcase.WithAttributes,
|
||||||
|
testresources.ResourcedTestCase, utils.DeployTestMixin):
|
||||||
|
"""This manager provides access to Murano-api service."""
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(MuranoTestsCore, cls).setUpClass()
|
||||||
|
|
||||||
|
cfg.load_config()
|
||||||
|
cls._environments = []
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(MuranoTestsCore, self).tearDown()
|
||||||
|
self.purge_environments()
|
||||||
|
|
||||||
|
# --------------------------Specific test methods------------------------------
|
||||||
|
|
||||||
|
def wait_for_environment_deploy(self, environment):
|
||||||
|
"""Wait for successful deployment of Murano environment.
|
||||||
|
|
||||||
|
Logging deployments and reports of failure.
|
||||||
|
:param environment: Murano environment
|
||||||
|
:return: Murano environment
|
||||||
|
"""
|
||||||
|
start_time = time.time()
|
||||||
|
status = environment.manager.get(environment.id).status
|
||||||
|
while status != 'ready':
|
||||||
|
status = environment.manager.get(environment.id).status
|
||||||
|
if time.time() - start_time > 1800:
|
||||||
|
time.sleep(60)
|
||||||
|
self._log_report(environment)
|
||||||
|
self.fail(
|
||||||
|
'Environment deployment is not finished in 1200 seconds')
|
||||||
|
elif status == 'deploy failure':
|
||||||
|
self._log_report(environment)
|
||||||
|
time.sleep(60)
|
||||||
|
self.fail('Environment has incorrect status {0}'.
|
||||||
|
format(status))
|
||||||
|
time.sleep(5)
|
||||||
|
LOG.debug('Environment {env_name} is ready'.format(
|
||||||
|
env_name=environment.name))
|
||||||
|
return environment.manager.get(environment.id)
|
||||||
|
|
||||||
|
def status_check(self, environment, configurations, kubernetes=False):
|
||||||
|
"""Function which gives opportunity to check any count of instances.
|
||||||
|
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param configurations: Array of configurations.
|
||||||
|
:param kubernetes: Used for parsing multiple instances in one service
|
||||||
|
False by default.
|
||||||
|
Example: [[instance_name, *ports], [instance_name, *ports]] ...
|
||||||
|
Example k8s: [[cluster['name'], instance_name, *ports], [...], ...]
|
||||||
|
"""
|
||||||
|
for configuration in configurations:
|
||||||
|
if kubernetes:
|
||||||
|
service_name = configuration[0]
|
||||||
|
LOG.debug('Service: {service_name}'.format(
|
||||||
|
service_name=service_name))
|
||||||
|
inst_name = configuration[1]
|
||||||
|
LOG.debug('Instance: {instance_name}'.format(
|
||||||
|
instance_name=inst_name))
|
||||||
|
ports = configuration[2:]
|
||||||
|
LOG.debug('Acquired ports: {ports}'.format(ports=ports))
|
||||||
|
ip = self.get_k8s_ip_by_instance_name(environment, inst_name,
|
||||||
|
service_name)
|
||||||
|
if ip and ports:
|
||||||
|
for port in ports:
|
||||||
|
self.check_port_access(ip, port)
|
||||||
|
self.check_k8s_deployment(ip, port)
|
||||||
|
else:
|
||||||
|
self.fail('Instance does not have floating IP')
|
||||||
|
else:
|
||||||
|
inst_name = configuration[0]
|
||||||
|
ports = configuration[1:]
|
||||||
|
ip = self.get_ip_by_instance_name(environment, inst_name)
|
||||||
|
if ip and ports:
|
||||||
|
for port in ports:
|
||||||
|
self.check_port_access(ip, port)
|
||||||
|
else:
|
||||||
|
self.fail('Instance does not have floating IP')
|
||||||
|
|
||||||
|
def deployment_success_check(self, environment, *ports):
|
||||||
|
"""Old style deployment check.
|
||||||
|
|
||||||
|
Checks that environment deployment successfully. Only one instance in
|
||||||
|
environment for this function is permitted for using this function.
|
||||||
|
:param environment: Murano environment
|
||||||
|
:param ports:
|
||||||
|
"""
|
||||||
|
deployment = self.murano_client().deployments.list(environment.id)[-1]
|
||||||
|
|
||||||
|
self.assertEqual('success', deployment.state,
|
||||||
|
'Deployment status is {0}'.format(deployment.state))
|
||||||
|
|
||||||
|
ip = environment.services[0]['instance']['floatingIpAddress']
|
||||||
|
|
||||||
|
if ip:
|
||||||
|
for port in ports:
|
||||||
|
self.check_port_access(ip, port)
|
||||||
|
else:
|
||||||
|
self.fail('Instance does not have floating IP')
|
||||||
|
|
||||||
|
def check_port_access(self, ip, port):
|
||||||
|
"""Check that ports are opened on specific instances.
|
||||||
|
|
||||||
|
:param ip: Instance's ip address
|
||||||
|
:param port: Port that you want to check
|
||||||
|
"""
|
||||||
|
result = 1
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < 600:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
result = sock.connect_ex((str(ip), port))
|
||||||
|
sock.close()
|
||||||
|
if result == 0:
|
||||||
|
break
|
||||||
|
time.sleep(5)
|
||||||
|
self.assertEqual(0, result, '%s port is closed on instance' % port)
|
||||||
|
|
||||||
|
def check_k8s_deployment(self, ip, port):
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < 600:
|
||||||
|
try:
|
||||||
|
LOG.debug('Checking: {ip}:{port}'.format(ip=ip, port=port))
|
||||||
|
self.verify_connection(ip, port)
|
||||||
|
return
|
||||||
|
except RuntimeError as e:
|
||||||
|
time.sleep(10)
|
||||||
|
LOG.debug(e)
|
||||||
|
self.fail('Containers are not ready')
|
||||||
|
|
||||||
|
def check_path(self, env, path, inst_name=None):
|
||||||
|
"""Check path of deployed application using requests method 'GET'.
|
||||||
|
|
||||||
|
:param env: Murano environment.
|
||||||
|
:param path: Path to check
|
||||||
|
Example: wordpress. e.g. function will check http://<ip>/wordpress
|
||||||
|
:param inst_name: If defined, function will search through environment
|
||||||
|
for instance ip and after check path.
|
||||||
|
"""
|
||||||
|
environment = env.manager.get(env.id)
|
||||||
|
if inst_name:
|
||||||
|
ip = self.get_ip_by_instance_name(environment, inst_name)
|
||||||
|
else:
|
||||||
|
ip = environment.services[0]['instance']['floatingIpAddress']
|
||||||
|
resp = requests.get('http://{0}/{1}'.format(ip, path))
|
||||||
|
if resp.status_code == 200:
|
||||||
|
return resp
|
||||||
|
else:
|
||||||
|
self.fail("Service path unavailable")
|
||||||
|
|
||||||
|
def deploy_environment(self, environment, session):
|
||||||
|
self.murano_client().sessions.deploy(environment.id, session.id)
|
||||||
|
return self.wait_for_environment_deploy(environment)
|
||||||
|
|
||||||
|
def _get_telnet_app(self):
|
||||||
|
return {
|
||||||
|
"instance": {
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.resources.LinuxMuranoInstance",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
},
|
||||||
|
"flavor": self.flavor,
|
||||||
|
"image": self.linux,
|
||||||
|
"name": "instance{0}".format(uuid.uuid4().hex[:5]),
|
||||||
|
},
|
||||||
|
"name": "app{0}".format(uuid.uuid4().hex[:5]),
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.linux.Telnet",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_test_app(self):
|
||||||
|
return {
|
||||||
|
"instance": {
|
||||||
|
"flavor": self.flavor,
|
||||||
|
"image": self.linux,
|
||||||
|
"assignFloatingIp": True,
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.resources.LinuxMuranoInstance",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
},
|
||||||
|
"name": self.rand_name('mrntest')
|
||||||
|
},
|
||||||
|
"name": self.rand_name('dummy'),
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.test.UpdateExecutor",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def upload_app(cls, app_dir, name, tags):
|
||||||
|
"""Zip and upload application to Murano
|
||||||
|
|
||||||
|
:param app_dir: Unzipped dir with an application
|
||||||
|
:param name: Application name
|
||||||
|
:param tags: Application tags
|
||||||
|
:return: Uploaded package
|
||||||
|
"""
|
||||||
|
zip_file_path = cls.zip_dir(os.path.dirname(__file__), app_dir)
|
||||||
|
cls.init_list("_package_files")
|
||||||
|
cls._package_files.append(zip_file_path)
|
||||||
|
return cls.upload_package(
|
||||||
|
name, tags, zip_file_path)
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as common_utils
|
||||||
|
import murano_tempest_tests.tests.functional.engine.manager as core
|
||||||
|
from nose.plugins.attrib import attr as tag
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageSupportTest(core.MuranoTestsCore):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(LanguageSupportTest, cls).setUpClass()
|
||||||
|
cls.linux = core.CONF.murano.linux_image
|
||||||
|
cls.flavor = core.CONF.murano.standard_flavor
|
||||||
|
cls.keyname = core.CONF.murano.keyname
|
||||||
|
cls.instance_type = core.CONF.murano.instance_type
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Upload the Murano test package.
|
||||||
|
cls.upload_app('io.murano.conflang.chef.ExampleChef',
|
||||||
|
'ExampleChef', {"tags": ["tag"]})
|
||||||
|
cls.upload_app('io.murano.conflang.puppet.ExamplePuppet',
|
||||||
|
'ExamplePuppet', {"tags": ["tag"]})
|
||||||
|
except Exception:
|
||||||
|
cls.tearDownClass()
|
||||||
|
raise
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
with common_utils.ignored(Exception):
|
||||||
|
try:
|
||||||
|
cls.purge_uploaded_packages()
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _test_deploy(self, environment_name, package_name, port):
|
||||||
|
post_body = {
|
||||||
|
"instance": {
|
||||||
|
"flavor": self.flavor,
|
||||||
|
"image": self.linux,
|
||||||
|
"keyname": self.keyname,
|
||||||
|
"assignFloatingIp": True,
|
||||||
|
'name': environment_name,
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.resources.ConfLangInstance",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"name": environment_name,
|
||||||
|
"port": port,
|
||||||
|
"?": {
|
||||||
|
"type": package_name,
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment_name = environment_name + uuid.uuid4().hex[:5]
|
||||||
|
environment = self.create_environment(name=environment_name)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
self.add_service(environment, post_body, session)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
self.wait_for_environment_deploy(environment)
|
||||||
|
self.deployment_success_check(environment, port)
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_deploy_example_chef_example(self):
|
||||||
|
self._test_deploy('chefExample',
|
||||||
|
'io.murano.conflang.chef.ExampleChef', 22)
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_deploy_example_puppet_example(self):
|
||||||
|
self._test_deploy('puppetExample',
|
||||||
|
"io.murano.conflang.puppet.ExamplePuppet", 22)
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Copyright (c) 2015 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from nose.plugins.attrib import attr as tag
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.engine.manager as core
|
||||||
|
|
||||||
|
|
||||||
|
class MuranoDeploymentTest(core.MuranoTestsCore):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(MuranoDeploymentTest, cls).setUpClass()
|
||||||
|
|
||||||
|
cls.linux = core.CONF.murano.linux_image
|
||||||
|
cls.flavor = core.CONF.murano.standard_flavor
|
||||||
|
|
||||||
|
cls.upload_app('io.murano.apps.test.UpdateExecutor',
|
||||||
|
'UpdateExecutor',
|
||||||
|
{"categories": ["Web"], "tags": ["tag"]})
|
||||||
|
|
||||||
|
cls.upload_app('io.murano.apps.test.Lighttpd',
|
||||||
|
'Lighttpd',
|
||||||
|
{"categories": ["Web"], "tags": ["tag"]})
|
||||||
|
|
||||||
|
cls.upload_app('io.murano.apps.test.ApacheHttpServerCustom',
|
||||||
|
'Apache HTTP Server Custom',
|
||||||
|
{"categories": ["Web"], "tags": ["test"]})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
super(MuranoDeploymentTest, cls).tearDownClass()
|
||||||
|
|
||||||
|
cls.purge_environments()
|
||||||
|
cls.purge_uploaded_packages()
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_app_deployment(self):
|
||||||
|
post_body = self.get_test_app()
|
||||||
|
environment_name = self.rand_name('dummyMurano')
|
||||||
|
environment = self.create_environment(name=environment_name)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
self.add_service(environment, post_body, session)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_resources_deallocation(self):
|
||||||
|
app_1 = self.get_test_app()
|
||||||
|
app_2 = self.get_test_app()
|
||||||
|
environment_name = self.rand_name('dummyMurano')
|
||||||
|
environment = self.create_environment(name=environment_name)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
self.add_service(environment, app_1, session)
|
||||||
|
self.add_service(environment, app_2, session)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
|
||||||
|
environment = self.get_environment(environment)
|
||||||
|
app_for_remove = self.get_service(environment, app_1['name'],
|
||||||
|
to_dict=False)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
environment = self.delete_service(environment, session, app_for_remove)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
|
||||||
|
instance_name = app_1['instance']['name']
|
||||||
|
stack = self._get_stack(environment.id)
|
||||||
|
template = self.get_stack_template(stack)
|
||||||
|
ip_addresses = '{0}-assigned-ip'.format(instance_name)
|
||||||
|
floating_ip = '{0}-FloatingIPaddress'.format(instance_name)
|
||||||
|
|
||||||
|
self.assertNotIn(ip_addresses, template['outputs'])
|
||||||
|
self.assertNotIn(floating_ip, template['outputs'])
|
||||||
|
self.assertNotIn(instance_name, template['resources'])
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_dependent_apps(self):
|
||||||
|
post_body = self.get_test_app()
|
||||||
|
environment_name = self.rand_name('dummyMurano')
|
||||||
|
environment = self.create_environment(name=environment_name)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
updater = self.add_service(environment, post_body, session,
|
||||||
|
to_dict=True)
|
||||||
|
post_body = {
|
||||||
|
"name": self.rand_name("lighttest"),
|
||||||
|
"updater": updater,
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.test.Lighttpd",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.add_service(environment, post_body, session)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
self.status_check(environment,
|
||||||
|
[[updater['instance']['name'], 22, 80]])
|
||||||
|
|
||||||
|
@tag('gate', 'all', 'coverage')
|
||||||
|
def test_simple_software_configuration(self):
|
||||||
|
post_body = {
|
||||||
|
"instance": {
|
||||||
|
"flavor": self.flavor,
|
||||||
|
"image": self.linux,
|
||||||
|
"assignFloatingIp": True,
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.resources.LinuxMuranoInstance",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
},
|
||||||
|
"name": self.rand_name("mrn-test"),
|
||||||
|
},
|
||||||
|
"name": self.rand_name("ssc-test"),
|
||||||
|
"userName": self.rand_name("user"),
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.test.ApacheHttpServerCustom",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
username = post_body["userName"]
|
||||||
|
environment_name = self.rand_name('SSC-murano')
|
||||||
|
environment = self.create_environment(name=environment_name)
|
||||||
|
session = self.create_session(environment)
|
||||||
|
self.add_service(environment, post_body, session, to_dict=True)
|
||||||
|
self.deploy_environment(environment, session)
|
||||||
|
self.status_check(environment,
|
||||||
|
[[post_body['instance']['name'], 22, 80]])
|
||||||
|
resp = self.check_path(environment, '', post_body['instance']['name'])
|
||||||
|
self.assertIn(username, resp.text, "Required information not found in "
|
||||||
|
"response from server")
|
|
@ -0,0 +1,157 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation, Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from keystoneclient import exceptions as keystone_exceptions
|
||||||
|
import mistralclient.api.client as mistralclient
|
||||||
|
import testresources
|
||||||
|
import testtools
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.tempest_utils \
|
||||||
|
as tempest_utils
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as utils
|
||||||
|
|
||||||
|
|
||||||
|
class MistralIntegration(testtools.TestCase, testtools.testcase.WithAttributes,
|
||||||
|
testresources.ResourcedTestCase,
|
||||||
|
tempest_utils.TempestDeployTestMixin):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@utils.memoize
|
||||||
|
def mistral_client(cls):
|
||||||
|
keystone_client = cls.keystone_client()
|
||||||
|
|
||||||
|
endpoint_type = 'publicURL'
|
||||||
|
service_type = 'workflowv2'
|
||||||
|
|
||||||
|
mistral_url = keystone_client.service_catalog.url_for(
|
||||||
|
service_type=service_type,
|
||||||
|
endpoint_type=endpoint_type)
|
||||||
|
|
||||||
|
auth_token = keystone_client.auth_token
|
||||||
|
|
||||||
|
return mistralclient.client(mistral_url=mistral_url,
|
||||||
|
auth_url=keystone_client.auth_url,
|
||||||
|
project_id=keystone_client.tenant_id,
|
||||||
|
endpoint_type=endpoint_type,
|
||||||
|
service_type=service_type,
|
||||||
|
auth_token=auth_token,
|
||||||
|
user_id=keystone_client.user_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def upload_mistral_showcase_app(cls):
|
||||||
|
app_dir = 'io.murano.apps.test.MistralShowcaseApp'
|
||||||
|
zip_file_path = cls.zip_dir(os.path.dirname(__file__), app_dir)
|
||||||
|
cls.init_list("_package_files")
|
||||||
|
cls._package_files.append(zip_file_path)
|
||||||
|
return cls.upload_package(
|
||||||
|
'MistralShowcaseApp',
|
||||||
|
{"categories": ["Web"], "tags": ["tag"]},
|
||||||
|
zip_file_path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_env_body():
|
||||||
|
return {
|
||||||
|
"name": "Mistral_environment",
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.test.MistralShowcaseApp",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CongressIntegration(testtools.TestCase,
|
||||||
|
testtools.testcase.WithAttributes,
|
||||||
|
testresources.ResourcedTestCase,
|
||||||
|
tempest_utils.TempestDeployTestMixin):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create_policy_req(cls, policy_name):
|
||||||
|
return {'abbreviation': None, 'kind': None,
|
||||||
|
'name': policy_name,
|
||||||
|
'description': None}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _upload_policy_enf_app(cls):
|
||||||
|
app_dir = 'io.murano.apps.test.PolicyEnforcementTestApp'
|
||||||
|
zip_file_path = cls.zip_dir(os.path.dirname(__file__), app_dir)
|
||||||
|
cls.init_list("_package_files")
|
||||||
|
cls._package_files.append(zip_file_path)
|
||||||
|
return cls.upload_package(
|
||||||
|
'PolicyEnforcementTestApp',
|
||||||
|
{"categories": ["Web"], "tags": ["tag"]},
|
||||||
|
zip_file_path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create_policy(cls, policy_names, kind=None):
|
||||||
|
for name in policy_names:
|
||||||
|
policy_req = {"name": name}
|
||||||
|
if kind:
|
||||||
|
policy_req["kind"] = kind
|
||||||
|
with utils.ignored(keystone_exceptions.Conflict):
|
||||||
|
cls.congress_client().create_policy(policy_req)
|
||||||
|
|
||||||
|
rules = []
|
||||||
|
rules_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"rules_" + name + ".txt")
|
||||||
|
|
||||||
|
if os.path.isfile(rules_file):
|
||||||
|
with open(rules_file) as f:
|
||||||
|
rules = [rule.strip() for rule in f.readlines()
|
||||||
|
if rule.strip()]
|
||||||
|
for rule in rules:
|
||||||
|
with utils.ignored(keystone_exceptions.Conflict):
|
||||||
|
cls.congress_client().create_policy_rule(name,
|
||||||
|
{'rule': rule})
|
||||||
|
|
||||||
|
def _create_test_app(self, flavor, key):
|
||||||
|
"""Application create request body
|
||||||
|
|
||||||
|
Deployment is expected to fail earlier due to policy violation.
|
||||||
|
Not existing image prevents real deployment to happen
|
||||||
|
in case that test goes wrong way.
|
||||||
|
|
||||||
|
:param flavor: instance image flavor
|
||||||
|
:param key: key name
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {
|
||||||
|
"instance": {
|
||||||
|
"flavor": flavor,
|
||||||
|
"keyname": key,
|
||||||
|
"image": "not_existing_image",
|
||||||
|
"assignFloatingIp": True,
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.resources.LinuxMuranoInstance",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
},
|
||||||
|
"name": "testMurano"
|
||||||
|
},
|
||||||
|
"name": "teMurano",
|
||||||
|
"?": {
|
||||||
|
"type": "io.murano.apps.test.PolicyEnforcementTestApp",
|
||||||
|
"id": str(uuid.uuid4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _check_deploy_failure(self, post_body, expected_text):
|
||||||
|
environment_name = 'PolicyEnfTestEnv' + uuid.uuid4().hex[:5]
|
||||||
|
env = self.deploy_apps(environment_name, post_body)
|
||||||
|
status = self.wait_for_final_status(env)
|
||||||
|
self.assertIn("failure", status[0], "Unexpected status : " + status[0])
|
||||||
|
self.assertIn(expected_text, status[1].lower(),
|
||||||
|
"Unexpected status : " + status[1])
|
|
@ -0,0 +1,32 @@
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.apps.test
|
||||||
|
std: io.murano
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: MistralShowcaseApp
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
|
||||||
|
mistralClient:
|
||||||
|
Contract: $.class(sys:MistralClient)
|
||||||
|
Usage: Runtime
|
||||||
|
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $environment: $.find(std:Environment).require()
|
||||||
|
- $this.mistralClient: new(sys:MistralClient, $environment)
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- $resources: new('io.murano.system.Resources')
|
||||||
|
- $workflow: $resources.string('TestEcho_MistralWorkflow.yaml')
|
||||||
|
- $.mistralClient.upload(definition => $workflow)
|
||||||
|
- $output: $.mistralClient.run(name => 'test_echo', inputs => dict(input_1 => input_1_value))
|
||||||
|
- $this.find(std:Environment).reporter.report($this, $output.get('out_3'))
|
|
@ -0,0 +1,24 @@
|
||||||
|
version: '2.0'
|
||||||
|
|
||||||
|
test_echo:
|
||||||
|
type: direct
|
||||||
|
input:
|
||||||
|
- input_1
|
||||||
|
output:
|
||||||
|
out_1: <% $.task1_output_1 %>
|
||||||
|
out_2: <% $.task2_output_2 %>
|
||||||
|
out_3: <% $.input_1 %>
|
||||||
|
tasks:
|
||||||
|
my_echo_test:
|
||||||
|
action: std.echo output='just a string'
|
||||||
|
publish:
|
||||||
|
task1_output_1: 'task1_output_1_value'
|
||||||
|
task1_output_2: 'task1_output_2_value'
|
||||||
|
on-success:
|
||||||
|
- my_echo_test_2
|
||||||
|
|
||||||
|
my_echo_test_2:
|
||||||
|
action: std.echo output='just a string'
|
||||||
|
publish:
|
||||||
|
task2_output_1: 'task2_output_1_value'
|
||||||
|
task2_output_2: 'task2_output_2_value'
|
|
@ -0,0 +1,10 @@
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.apps.test.MistralShowcaseApp
|
||||||
|
Name: MistralShowcaseApp
|
||||||
|
Description: |
|
||||||
|
MistralShowcaseApp.
|
||||||
|
Author: 'Mirantis, Inc'
|
||||||
|
Tags: [Servlets, Server, Pages, Java]
|
||||||
|
Classes:
|
||||||
|
io.murano.apps.test.MistralShowcaseApp: MistralShowcaseApp.yaml
|
|
@ -0,0 +1,48 @@
|
||||||
|
Namespaces:
|
||||||
|
=: io.murano.apps.test
|
||||||
|
std: io.murano
|
||||||
|
res: io.murano.resources
|
||||||
|
sys: io.murano.system
|
||||||
|
|
||||||
|
|
||||||
|
Name: PolicyEnforcementTestApp
|
||||||
|
|
||||||
|
Extends: std:Application
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
name:
|
||||||
|
Contract: $.string().notNull()
|
||||||
|
|
||||||
|
instance:
|
||||||
|
Contract: $.class(res:Instance).notNull()
|
||||||
|
|
||||||
|
host:
|
||||||
|
Contract: $.string()
|
||||||
|
Usage: Out
|
||||||
|
|
||||||
|
user:
|
||||||
|
Contract: $.string()
|
||||||
|
Usage: Out
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
initialize:
|
||||||
|
Body:
|
||||||
|
- $._environment: $.find(std:Environment).require()
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
Body:
|
||||||
|
- If: not $.getAttr(deployed, false)
|
||||||
|
Then:
|
||||||
|
- $._environment.reporter.report($this, 'Creating VM')
|
||||||
|
- $securityGroupIngress:
|
||||||
|
- ToPort: 22
|
||||||
|
FromPort: 22
|
||||||
|
IpProtocol: tcp
|
||||||
|
External: true
|
||||||
|
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
|
||||||
|
- $.instance.deploy()
|
||||||
|
- $resources: new(sys:Resources)
|
||||||
|
- $._environment.reporter.report($this, 'Test VM is installed')
|
||||||
|
- $.host: $.instance.ipAddresses[0]
|
||||||
|
- $.user: 'root'
|
||||||
|
- $.setAttr(deployed, true)
|
|
@ -0,0 +1,10 @@
|
||||||
|
Format: 1.0
|
||||||
|
Type: Application
|
||||||
|
FullName: io.murano.apps.test.PolicyEnforcementTestApp
|
||||||
|
Name: PolicyEnforcementTestApp
|
||||||
|
Description: |
|
||||||
|
This is a simple test app with a single VM for policy enforcement testing purposes.
|
||||||
|
Author: 'Hewlett-Packard'
|
||||||
|
Tags: [test]
|
||||||
|
Classes:
|
||||||
|
io.murano.apps.test.PolicyEnforcementTestApp: PolicyEnforcementTestApp.yaml
|
|
@ -0,0 +1,18 @@
|
||||||
|
action("deleteEnv")
|
||||||
|
|
||||||
|
murano:states-(eid,st) :- deleteEnv(eid), murano:states( eid, st)
|
||||||
|
|
||||||
|
murano:parent_types-(tid, type) :- deleteEnv(eid), murano:connected(eid, tid),murano:parent_types(tid,type)
|
||||||
|
murano:parent_types-(eid, type) :- deleteEnv(eid), murano:parent_types(eid,type)
|
||||||
|
|
||||||
|
murano:properties-(oid, pn, pv) :- deleteEnv(eid), murano:connected( eid, oid),murano:properties(oid, pn, pv)
|
||||||
|
murano:properties-(eid, pn, pv) :- deleteEnv(eid), murano:properties(eid, pn, pv)
|
||||||
|
|
||||||
|
murano:objects-(oid, pid, ot) :- deleteEnv(eid), murano:connected(eid, oid), murano:objects(oid, pid, ot)
|
||||||
|
murano:objects-(eid, tnid, ot) :- deleteEnv(eid), murano:objects(eid, tnid, ot)
|
||||||
|
|
||||||
|
murano:relationships-(sid,tid, rt) :- deleteEnv(eid), murano:connected( eid, sid), murano:relationships( sid, tid, rt)
|
||||||
|
murano:relationships-(eid,tid, rt) :- deleteEnv(eid), murano:relationships( eid, tid, rt)
|
||||||
|
|
||||||
|
murano:connected-(tid, tid2) :- deleteEnv(eid), murano:connected(eid, tid), murano:connected(tid,tid2)
|
||||||
|
murano:connected-(eid,tid) :- deleteEnv(eid), murano:connected(eid,tid)
|
|
@ -0,0 +1,7 @@
|
||||||
|
missing_key("")
|
||||||
|
invalid_flavor_name("really.bad.flavor")
|
||||||
|
predeploy_errors(eid, obj_id, msg):-murano:objects(obj_id, pid, type), murano_env_of_object(obj_id, eid), murano:properties(obj_id, "flavor", flavor_name), invalid_flavor_name(flavor_name), murano:properties(obj_id, "name", obj_name), concat(obj_name, ": bad flavor", msg)
|
||||||
|
predeploy_errors(eid, obj_id, msg):-murano:objects(obj_id, pid, type), murano_env_of_object(obj_id, eid), murano:properties(obj_id, "keyname", key_name), missing_key(key_name), murano:properties(obj_id, "name", obj_name), concat(obj_name, ": missing key", msg)
|
||||||
|
murano_env_of_object(oid,eid):-murano:connected(eid,oid), murano:objects(eid,tid,"io.murano.Environment")
|
||||||
|
bad_flavor_synonyms("horrible.flavor")
|
||||||
|
predeploy_modify(eid, obj_id, action):-murano:objects(obj_id, pid, type), murano_env_of_object(obj_id, eid), murano:properties(obj_id, "flavor", flavor_name), bad_flavor_synonyms(flavor_name), concat("set-property: {object_id: ", obj_id, first_part ), concat(first_part, ", prop_name: flavor, value: really.bad.flavor}", action)
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from nose.plugins.attrib import attr as tag
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as common_utils
|
||||||
|
import murano_tempest_tests.tests.functional.integration.integration_base \
|
||||||
|
as core
|
||||||
|
|
||||||
|
|
||||||
|
class MistralTest(core.MistralIntegration):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(MistralTest, cls).setUpClass()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Upload the Murano test package.
|
||||||
|
cls.upload_mistral_showcase_app()
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
cls.tearDownClass()
|
||||||
|
raise
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
with common_utils.ignored(Exception):
|
||||||
|
cls.purge_environments()
|
||||||
|
with common_utils.ignored(Exception):
|
||||||
|
cls.purge_uploaded_packages()
|
||||||
|
|
||||||
|
@tag('all', 'coverage')
|
||||||
|
def test_deploy_package_success(self):
|
||||||
|
# Test expects successful deployment and one output: input_1_value.
|
||||||
|
|
||||||
|
# Create env json string.
|
||||||
|
post_body = self._create_env_body()
|
||||||
|
|
||||||
|
environment_name = 'Mistral_environment' + uuid.uuid4().hex[:5]
|
||||||
|
|
||||||
|
# Deploy the environment.
|
||||||
|
env = self.deploy_apps(environment_name, post_body)
|
||||||
|
|
||||||
|
status = self.wait_for_final_status(env)
|
||||||
|
|
||||||
|
self.assertIn("ready", status[0],
|
||||||
|
"Unexpected status : " + status[0])
|
||||||
|
self.assertIn("input_1_value", status[1],
|
||||||
|
"Unexpected output value: " + status[1])
|
|
@ -0,0 +1,89 @@
|
||||||
|
# Copyright (c) 2015 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import muranoclient.common.exceptions as murano_exceptions
|
||||||
|
from nose.plugins.attrib import attr as tag
|
||||||
|
|
||||||
|
import murano_tempest_tests.tests.functional.common.utils as common_utils
|
||||||
|
import murano_tempest_tests.tests.functional.integration.integration_base \
|
||||||
|
as core
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyEnforcementTest(core.CongressIntegration):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(PolicyEnforcementTest, cls).setUpClass()
|
||||||
|
|
||||||
|
cls._create_policy(["murano", "murano_system"])
|
||||||
|
cls._create_policy(["murano_action"], kind="action")
|
||||||
|
|
||||||
|
with common_utils.ignored(murano_exceptions.HTTPInternalServerError):
|
||||||
|
cls._upload_policy_enf_app()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
cls.purge_uploaded_packages()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(PolicyEnforcementTest, self).tearDown()
|
||||||
|
self.purge_environments()
|
||||||
|
|
||||||
|
@tag('all', 'coverage')
|
||||||
|
def test_deploy_policy_fail_key(self):
|
||||||
|
"""Test expects failure due to empty key name.
|
||||||
|
|
||||||
|
In rules_murano_system.txt file are defined congress
|
||||||
|
rules preventing deploy environment where instances
|
||||||
|
have empty keyname property. In other words admin
|
||||||
|
prevented spawn instance without assigned key pair.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._check_deploy_failure(
|
||||||
|
self._create_test_app(key='',
|
||||||
|
flavor='m1.small'),
|
||||||
|
'missing key')
|
||||||
|
|
||||||
|
@tag('all', 'coverage')
|
||||||
|
def test_deploy_policy_fail_flavor(self):
|
||||||
|
"""Test expects failure due to blacklisted flavor
|
||||||
|
|
||||||
|
In rules_murano_system.txt file are defined congress
|
||||||
|
rules preventing deploy environment where instances
|
||||||
|
have flavor property set to 'really.bad.flavor'.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._check_deploy_failure(
|
||||||
|
self._create_test_app(flavor='really.bad.flavor',
|
||||||
|
key='test-key'),
|
||||||
|
'bad flavor')
|
||||||
|
|
||||||
|
@tag('all', 'coverage')
|
||||||
|
def test_set_property_policy(self):
|
||||||
|
"""Tests environment modification by policy
|
||||||
|
|
||||||
|
In rules_murano_system.txt file are defined congress
|
||||||
|
rules changing flavor property. There are defined
|
||||||
|
synonyms for 'really.bad.flavor'. One of such synonyms
|
||||||
|
is 'horrible.flavor' Environment is modified prior deployment.
|
||||||
|
The synonym name 'horrible.flavor' is set to original
|
||||||
|
value 'really.bad.flavor' and then deployment is aborted
|
||||||
|
because instances of 'really.bad.flavor' are prevented
|
||||||
|
to be deployed like for the test above.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._check_deploy_failure(
|
||||||
|
self._create_test_app(key="test-key",
|
||||||
|
flavor="horrible.flavor"),
|
||||||
|
"bad flavor")
|
|
@ -10,3 +10,12 @@ oslo.utils>=3.33.0 # Apache-2.0
|
||||||
testtools>=2.2.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
tempest>=17.1.0 # Apache-2.0
|
tempest>=17.1.0 # Apache-2.0
|
||||||
requests>=2.14.2 # Apache-2.0
|
requests>=2.14.2 # Apache-2.0
|
||||||
|
nose>=1.3.7 # LGPL
|
||||||
|
testresources>=2.0.0 # Apache-2.0/BSD
|
||||||
|
|
||||||
|
python-keystoneclient>=3.8.0 # Apache-2.0
|
||||||
|
python-heatclient>=1.10.0 # Apache-2.0
|
||||||
|
python-neutronclient>=6.7.0 # Apache-2.0
|
||||||
|
python-muranoclient>=0.8.2 # Apache-2.0
|
||||||
|
python-congressclient<2000,>=1.9.0 # Apache-2.0
|
||||||
|
python-mistralclient!=3.2.0,>=3.1.0 # Apache-2.0
|
||||||
|
|
Loading…
Reference in New Issue