Merge "Remove congress and mistral functional integration tests"

This commit is contained in:
Zuul 2018-08-07 03:30:39 +00:00 committed by Gerrit Code Review
commit ba9f53100e
55 changed files with 17 additions and 2810 deletions

View File

@ -1,18 +0,0 @@
#!/bin/bash
# This script is executed inside post_test_hook function in devstack gate.
cd /opt/stack/new/murano/functionaltests
# Allow to execute other run_tests_*.sh script based on first parameter
RUN_TEST_SUFFIX=""
if [ "$#" -ge 1 ]; then
RUN_TEST_SUFFIX=_$1
fi
sudo ./run_tests$RUN_TEST_SUFFIX.sh
RETVAL=$?
# Copy tempest log files to be published among other logs upon job completion
sudo cp /opt/stack/new/murano/functionaltests/tempest.log /opt/stack/logs
exit $RETVAL

View File

@ -1,8 +0,0 @@
#!/bin/bash
# This script is executed inside pre_test_hook function in devstack gate.
# Install Murano devstack integration
. ./pre_test_hook_common.sh
MURANO_BASE=/opt/stack/new/murano/contrib/devstack

View File

@ -1,3 +0,0 @@
#!/bin/bash
DEVSTACK_BASE=/opt/stack/new/devstack

View File

@ -1,6 +0,0 @@
#!/bin/bash
# Install Congress devstack integration
. ./pre_test_hook_common.sh
CONGRESS_BASE=/opt/stack/new/congress/contrib/devstack

View File

@ -1,5 +0,0 @@
#!/bin/bash
# Install Mistral devstack integration
. ./pre_test_hook_common.sh
MISTRAL_BASE=/opt/stack/new/mistral/contrib/devstack

View File

@ -1,16 +0,0 @@
#!/bin/bash
# Intended be sourced by other scripts
# How many seconds to wait for the API to be responding before giving up
API_RESPONDING_TIMEOUT=20
if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "while ! curl -s http://127.0.0.1/application-catalog/v1/ 2>/dev/null | grep -q 'Unauthorized' ; do sleep 1; done"; then
echo "Murano API failed to respond within ${API_RESPONDING_TIMEOUT} seconds"
exit 1
fi
echo "Successfully contacted Murano API"
# Where tempest code lives
TEMPEST_DIR=${TEMPEST_DIR:-/opt/stack/new/tempest}

View File

@ -1,17 +0,0 @@
#!/bin/bash
. ./run_tests_common.sh
# Add tempest source tree to PYTHONPATH
export PYTHONPATH=$PYTHONPATH:$TEMPEST_DIR
# Add tempest config file path to env variables
export TEMPEST_CONFIG_DIR=${TEMPEST_CONFIG_DIR:-$TEMPEST_DIR/etc/}
#installing requirements for tempest
pip install -r $TEMPEST_DIR/requirements.txt
#installing test requirements for murano
pip install -r ../test-requirements.txt
nosetests -sv ../murano/tests/functional/integration/test_policy_enf.py ../murano/tests/functional/integration/test_mistral.py

View File

@ -0,0 +1,6 @@
=====
MOVED
=====
The Congress and Mistral functional integration tests has moved to
http://git.openstack.org/cgit/openstack/murano-tempest-plugin

View File

@ -1,49 +0,0 @@
# 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.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')

View File

@ -1,546 +0,0 @@
# 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 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.v2_0 as keystoneclientv2
import keystoneclient.v3 as keystoneclientv3
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
import yaml
from murano.services import states
import murano.tests.functional.common.zip_utils_mixin as zip_utils
import murano.tests.functional.engine.config as cfg
CONF = cfg.cfg.CONF
LOG = logging.getLogger(__name__)
@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):
cfg.load_config()
# -----------------------------Clients methods---------------------------------
@staticmethod
@memoize
def keystone_client():
region = CONF.murano.region_name
if re.match(".*/v3/?$", CONF.murano.auth_url):
ksclient = keystoneclientv3
else:
ksclient = keystoneclientv2
return ksclient.Client(username=CONF.murano.user,
password=CONF.murano.password,
tenant_name=CONF.murano.tenant,
auth_url=CONF.murano.auth_url,
region_name=region)
@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 states.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)

View File

@ -1,30 +0,0 @@
# 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

View File

@ -1,45 +0,0 @@
[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

View File

@ -1,88 +0,0 @@
# 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)

View File

@ -1,81 +0,0 @@
# 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)

View File

@ -1,175 +0,0 @@
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.

View File

@ -1,8 +0,0 @@
<!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>

View File

@ -1,28 +0,0 @@
# 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

View File

@ -1,55 +0,0 @@
# 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)

View File

@ -1,175 +0,0 @@
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.

View File

@ -1,27 +0,0 @@
# 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

View File

@ -1,14 +0,0 @@
#!/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

View File

@ -1,24 +0,0 @@
# 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:

View File

@ -1,47 +0,0 @@
# 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)

View File

@ -1,175 +0,0 @@
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.

View File

@ -1,30 +0,0 @@
# 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

View File

@ -1,14 +0,0 @@
#!/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

View File

@ -1,22 +0,0 @@
# 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

View File

@ -1,48 +0,0 @@
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)

View File

@ -1,22 +0,0 @@
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

View File

@ -1,7 +0,0 @@
= DESCRIPTION:
= REQUIREMENTS:
= ATTRIBUTES:
= USAGE:

View File

@ -1,8 +0,0 @@
#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"

View File

@ -1,10 +0,0 @@
script "install" do
interpreter "bash"
user "root"
cwd "/opt"
code <<-EOH
echo test install
EOH
end
node.normal['test']['action_test'] = "install"

View File

@ -1,10 +0,0 @@
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

View File

@ -1,46 +0,0 @@
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)

View File

@ -1,20 +0,0 @@
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

View File

@ -1,4 +0,0 @@
class test::install($version='default_version'){
notify {"version: test":}
}

View File

@ -1,10 +0,0 @@
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

View File

@ -1,238 +0,0 @@
# 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.tests.functional.common.utils as utils
import murano.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)

View File

@ -1,87 +0,0 @@
# 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.tests.functional.common.utils as common_utils
import murano.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)

View File

@ -1,138 +0,0 @@
# 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.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")

View File

@ -1,156 +0,0 @@
# 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.tests.functional.common.tempest_utils as tempest_utils
import murano.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])

View File

@ -1,32 +0,0 @@
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'))

View File

@ -1,24 +0,0 @@
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'

View File

@ -1,10 +0,0 @@
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

View File

@ -1,48 +0,0 @@
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)

View File

@ -1,10 +0,0 @@
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

View File

@ -1,18 +0,0 @@
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)

View File

@ -1,7 +0,0 @@
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)

View File

@ -1,61 +0,0 @@
# 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.tests.functional.common.utils as common_utils
import murano.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])

View File

@ -1,88 +0,0 @@
# 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.tests.functional.common.utils as common_utils
import murano.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")

View File

@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import random
try:
from mistralclient.api import client as mistralcli
except ImportError as mistral_import_error:
@ -26,12 +28,19 @@ from murano.dsl import murano_method
from murano.dsl import murano_type
from murano.engine.system import workflowclient
from murano.tests.functional.common import utils as test_utils
from murano.tests.unit import base
CONF = cfg.CONF
rand_name = test_utils.DeployTestMixin.rand_name
def rand_name(name='murano'):
"""Generates random string.
:param name: Basic name
:return:
"""
return name + str(random.randint(1, 0x7fffffff))
class TestMistralClient(base.MuranoTestCase):