Enable getting data from metadatarepository

Modify unit tests

Change-Id: I75a71b48475b75ca6603756c33fad3742fea2900
This commit is contained in:
Ekaterina Fedorova 2013-10-24 13:46:02 +04:00
parent ce869822e4
commit bf2cc47a7e
22 changed files with 430 additions and 46 deletions

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="file" xsi:type="File" fileName="${basedir}/log.txt"
layout="${date} ${level}: &lt;${logger:shortName=true}&gt; ${message} ${exception:format=tostring}"/>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>
<appSettings>
<add key="rabbitmq.host" value="%RABBITMQ_HOST%"/>
<add key="rabbitmq.port" value="%RABBITMQ_PORT%"/>
<add key="rabbitmq.user" value="%RABBITMQ_USER%"/>
<add key="rabbitmq.password" value="%RABBITMQ_PASSWORD%"/>
<add key="rabbitmq.vhost" value="%RABBITMQ_VHOST%"/>
<add key="rabbitmq.inputQueue" value="%RABBITMQ_INPUT_QUEUE%"/>
<add key="rabbitmq.resultExchange" value=""/>
<add key="rabbitmq.resultRoutingKey" value="%RESULT_QUEUE%"/>
<add key="rabbitmq.durableMessages" value="true"/>
<add key="rabbitmq.ssl" value="%RABBITMQ_SSL%"/>
<add key="rabbitmq.allowInvalidCA" value="true"/>
<add key="rabbitmq.sslServerName" value=""/>
</appSettings>
</configuration>

View File

@ -0,0 +1,8 @@
RABBITMQ_HOST = "%RABBITMQ_HOST%"
RABBITMQ_PORT = "%RABBITMQ_PORT%"
RABBITMQ_USERNAME = "%RABBITMQ_USER%"
RABBITMQ_PASSWORD = "%RABBITMQ_PASSWORD%"
RABBITMQ_VHOST = "%RABBITMQ_VHOST%"
RABBITMQ_INPUT_QUEUE = "%RABBITMQ_INPUT_QUEUE%"
RESULT_QUEUE = "%RESULT_QUEUE%"
RABBITMQ_RESULT_ROUTING_KEY = "%RESULT_QUEUE%"

View File

@ -0,0 +1,35 @@
[DEFAULT]
debug=True
verbose=True
log_file = /var/log/murano-agnet.log
storage=/var/murano/plans
[rabbitmq]
# Input queue name
input_queue = %RABBITMQ_INPUT_QUEUE%
# Output routing key (usually queue name)
result_routing_key = %RESULT_QUEUE%
# Connection parameters to RabbitMQ service
# Hostname or IP address where RabbitMQ is located.
host = %RABBITMQ_HOST%
# RabbitMQ port (5672 is a default)
port = %RABBITMQ_PORT%
# Use SSL for RabbitMQ connections (True or False)
ssl = %RABBITMQ_SSL%
# Path to SSL CA certificate or empty to allow self signed server certificate
ca_certs =
# RabbitMQ credentials. Fresh RabbitMQ installation has "guest" account with "guest" password.
login = %RABBITMQ_USER%
password = %RABBITMQ_PASSWORD%
# RabbitMQ virtual host (vhost). Fresh RabbitMQ installation has "/" vhost preconfigured.
virtual_host = %RABBITMQ_VHOST%

View File

@ -7,9 +7,18 @@ log_file = /tmp/conductor.log
debug=True
verbose=True
# Directory where conductor's data directory located.
# "data" must be subdirectory to this.
data_dir = /etc/murano-conductor
# Provide directory with initialization scripts
init_scripts_dir = ./etc/init-scripts
# Provide directory with agent configs
agent_config_dir = ./etc/agent-config
# Provide absolute or relative path to data storing
# directory (may not be exist)
data_dir = test_data
# Provide url to Murano Metadata repository
murano_metadata_url = http://localhost:8084
# Maximum number of environments that can be processed simultaneously
max_environments = 20
@ -45,7 +54,7 @@ endpoint_type = publicURL
[rabbitmq]
# Connection parameters to RabbitMQ service
# Hostname or IP address where RabbitMQ is located.
# Hostname or IP address where RabbitMQ is located.
# !!! Change localhost to your real IP or hostname as this address must be reachable from VMs !!!
host = localhost

View File

@ -0,0 +1,11 @@
#!/bin/sh
AgentConfigBase64='%AGENT_CONFIG_BASE64%'
mkdir /etc/murano
echo $AgentConfigBase64 | base64 -d > /etc/murano/agent.config
chmod 664 /etc/murano/agent.config
sleep 10
reboot

68
etc/init-scripts/init.ps1 Normal file
View File

@ -0,0 +1,68 @@
#ps1
$WindowsAgentConfigBase64 = '%AGENT_CONFIG_BASE64%'
$WindowsAgentConfigFile = "C:\Murano\Agent\WindowsAgent.exe.config"
$WindowsAgentLogFile = "C:\Murano\Agent\log.txt"
$NewComputerName = '%INTERNAL_HOSTNAME%'
$MuranoFileShare = '\\%MURANO_SERVER_ADDRESS%\share'
$CaRootCertBase64 = "%CA_ROOT_CERT_BASE64%"
$CaRootCertFile = "C:\Murano\ca.cert"
$RestartRequired = $false
Import-Module CoreFunctions
Initialize-Logger 'CloudBase-Init' 'C:\Murano\PowerShell.log'
$ErrorActionPreference = 'Stop'
trap {
Write-LogError '<exception>'
Write-LogError $_ -EntireObject
Write-LogError '</exception>'
exit 1
}
Write-Log "Importing CA certificate ..."
if ($CaRootCertBase64 -eq '') {
Write-Log "Importing CA certificate ... skipped"
}
else {
ConvertFrom-Base64String -Base64String $CaRootCertBase64 -Path $CaRootCertFile
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $CaRootCertFile
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("AuthRoot","LocalMachine")
$store.Open("MaxAllowed")
$store.Add($cert)
$store.Close()
Write-Log "Importing CA certificate ... done"
}
Write-Log "Updating Murano Windows Agent."
Stop-Service "Murano Agent"
Backup-File $WindowsAgentConfigFile
Remove-Item $WindowsAgentConfigFile -Force
Remove-Item $WindowsAgentLogFile -Force
ConvertFrom-Base64String -Base64String $WindowsAgentConfigBase64 -Path $WindowsAgentConfigFile
Exec sc.exe 'config','"Murano Agent"','start=','delayed-auto'
Write-Log "Service has been updated."
Write-Log "Adding environment variable 'MuranoFileShare' = '$MuranoFileShare' ..."
[Environment]::SetEnvironmentVariable('MuranoFileShare', $MuranoFileShare, [EnvironmentVariableTarget]::Machine)
Write-Log "Environment variable added."
Write-Log "Renaming computer to '$NewComputerName' ..."
$null = Rename-Computer -NewName $NewComputerName -Force
Write-Log "New name assigned, restart required."
$RestartRequired = $true
Write-Log 'All done!'
if ( $RestartRequired ) {
Write-Log "Restarting computer ..."
Restart-Computer -Force
}
else {
Start-Service 'Murano Agent'
}

View File

@ -0,0 +1,6 @@
#!/bin/sh
AgentConfigBase64='%AGENT_CONFIG_BASE64%'
service murano-agent stop
echo $AgentConfigBase64 | base64 -d > /etc/murano-agent.conf
service murano-agent start

View File

@ -47,7 +47,6 @@ class MuranoEnvironment(resource.Resource):
except HTTPNotFound:
pass
def _find_environment(self, client):
environments = client.environments.list()
for environment in environments:
@ -75,10 +74,10 @@ class MuranoEnvironment(resource.Resource):
delay = 2
while True:
environment = client.environments.get(environment_id)
if environment.status == 'pending' and i > 5*60:
if environment.status == 'pending' and i > 5 * 60:
raise EnvironmentError(
"Environment deployment hasn't started")
elif environment.status == 'deploying' and i > 65*60:
elif environment.status == 'deploying' and i > 65 * 60:
raise EnvironmentError(
"Environment deployment takes too long")
elif environment.status == 'ready':

View File

@ -15,7 +15,6 @@
import glob
import sys
import traceback
import anyjson
import eventlet
@ -28,7 +27,7 @@ import reporting
from muranocommon.messaging import MqClient, Message
from muranoconductor import config as cfg
from muranocommon.helpers.token_sanitizer import TokenSanitizer
from muranoconductor import metadata
import vm_agent
import cloud_formation
@ -80,23 +79,29 @@ class ConductorWorkflowService(service.Service):
message_id = message.id
do_ack = False
reporter = None
with self.create_rmq_client() as mq:
try:
secure_task = TokenSanitizer().sanitize(task)
log.info('Starting processing task {0}: {1}'.format(
message_id, anyjson.dumps(secure_task)))
reporter = reporting.Reporter(mq, message_id, task['id'])
config = Config()
metadata_version = metadata.get_metadata(task['id'],
task['token'])
command_dispatcher = CommandDispatcher('e' + task['id'], mq,
task['token'],
task['tenant_id'],
reporter)
workflows = []
for path in glob.glob("data/workflows/*.xml"):
config = Config()
for path in glob.glob(
'{0}/workflows/*.xml'.format(metadata_version)):
log.debug('Loading XML {0}'.format(path))
workflow = Workflow(path, task, command_dispatcher, config,
reporter)
reporter, metadata_version)
workflows.append(workflow)
stop = False
@ -131,9 +136,11 @@ class ConductorWorkflowService(service.Service):
if stop:
log.info("Workflow stopped by 'stop' command")
do_ack = True
metadata.release(task['id'])
except Exception as ex:
log.exception(ex)
log.debug("Non-processable message detected, will ack message")
log.debug("Non-processable message detected, "
"will ack message")
do_ack = True
finally:
if do_ack:

View File

@ -14,14 +14,14 @@
# limitations under the License.
import base64
import config
from os.path import basename
import random
import string
import time
import datetime
import xml_code_engine
from openstack.common import log as logging
from muranoconductor import config as cfg
log = logging.getLogger(__name__)
@ -29,6 +29,7 @@ log = logging.getLogger(__name__)
def update_cf_stack(engine, context, body, template, result=None, error=None,
**kwargs):
command_dispatcher = context['/commandDispatcher']
metadata_id = context['/metadata_id']
def callback(result_value, error_result=None):
if result is not None:
@ -60,7 +61,8 @@ def update_cf_stack(engine, context, body, template, result=None, error=None,
name='cf', command='CreateOrUpdate', template=template,
mappings=(kwargs.get('mappings') or {}),
arguments=(kwargs.get('arguments') or {}),
callback=callback)
callback=callback,
metadata_id=metadata_id)
def delete_cf_stack(engine, context, body, **kwargs):
@ -77,11 +79,13 @@ def delete_cf_stack(engine, context, body, **kwargs):
def prepare_user_data(context, hostname, service, unit,
template='Default', initFile='init.ps1', **kwargs):
settings = config.CONF.rabbitmq
with open('data/{0}'.format(initFile)) as init_script_file:
with open('data/templates/agent-config/{0}.template'.format(
template)) as template_file:
settings = cfg.CONF.rabbitmq
path_to_init_file = '{0}/{1}'.format(basename(cfg.CONF.init_scripts_dir),
initFile)
with open(path_to_init_file) as init_script_file:
with open('{0}/{1}.template'.format(
basename(cfg.CONF.agent_config_dir), template)
) as template_file:
init_script = init_script_file.read()
template_data = template_file.read()
@ -108,7 +112,7 @@ def prepare_user_data(context, hostname, service, unit,
init_script = init_script.replace('%INTERNAL_HOSTNAME%', hostname)
init_script = init_script.replace(
'%MURANO_SERVER_ADDRESS%',
config.CONF.file_server or settings.host)
cfg.CONF.file_server or settings.host)
init_script = init_script.replace(
'%CA_ROOT_CERT_BASE64%',
@ -124,7 +128,7 @@ def set_config_params(template_data, replacements):
def get_ca_certificate():
ca_file = (config.CONF.rabbitmq.ca_certs or '').strip()
ca_file = (cfg.CONF.rabbitmq.ca_certs or '').strip()
if not ca_file:
return ''
with open(ca_file) as stream:

View File

@ -31,12 +31,13 @@ from muranoconductor import config
from muranoconductor.openstack.common import log
from muranoconductor.openstack.common import service
from muranoconductor.app import ConductorWorkflowService
from muranoconductor import metadata
def main():
try:
config.parse_args()
os.chdir(config.CONF.data_dir)
metadata.prepare(config.CONF.data_dir)
log.setup('conductor')
launcher = service.ServiceLauncher()
launcher.launch_service(ConductorWorkflowService())

View File

@ -77,12 +77,16 @@ class HeatExecutor(CommandBase):
kwargs.get('mappings') or {}),
muranoconductor.helpers.str2unicode(
kwargs.get('arguments') or {}),
callback)
callback,
kwargs['metadata_id'])
elif command == 'Delete':
return self._execute_delete(callback)
def _execute_create_update(self, template, mappings, arguments, callback):
with open('data/templates/cf/%s.template' % template) as template_file:
def _execute_create_update(self, template, mappings,
arguments, callback, metadata_id):
template_path = '{0}/templates/cf/{1}.template'.format(metadata_id,
template)
with open(template_path) as template_file:
template_data = template_file.read()
template_data = muranoconductor.helpers.transform_json(

View File

@ -19,12 +19,13 @@ import vm_agent
class CommandDispatcher(command.CommandBase):
def __init__(self, environment, rmqclient, token, tenant_id, reporter):
def __init__(self, environment, rmqclient, token,
tenant_id, reporter):
self._command_map = {
'cf': cloud_formation.HeatExecutor(environment, token, tenant_id,
reporter),
'agent': vm_agent.VmAgentExecutor(
environment, rmqclient, reporter)
'agent': vm_agent.VmAgentExecutor(environment, rmqclient,
reporter)
}
def execute(self, name, **kwargs):

View File

@ -21,9 +21,11 @@ class VmAgentExecutor(CommandBase):
self._reporter = reporter
rmqclient.declare(self._results_queue)
def execute(self, template, mappings, unit, service, callback,
def execute(self, template, mappings, unit, service, callback, metadata_id,
timeout=None):
template_path = 'data/templates/agent/%s.template' % template
template_path = '{0}/templates/agent/{1}.template'.format(metadata_id,
template)
#with open(template_path) as t_file:
# template_data = t_file.read()
#

View File

@ -34,6 +34,12 @@ paste_deploy_opts = [
cfg.StrOpt('config_file'),
]
directories = [
cfg.StrOpt('data_dir', default='program_data'),
cfg.StrOpt('init_scripts_dir', default='./etc/init-scripts'),
cfg.StrOpt('agent_config_dir', default='./etc/agent-config'),
]
rabbit_opts = [
cfg.StrOpt('host', default='localhost'),
cfg.IntOpt('port', default=5672),
@ -65,8 +71,10 @@ CONF.register_opts(paste_deploy_opts, group='paste_deploy')
CONF.register_opts(rabbit_opts, group='rabbitmq')
CONF.register_opts(heat_opts, group='heat')
CONF.register_opts(keystone_opts, group='keystone')
CONF.register_opts(directories)
CONF.register_opt(cfg.StrOpt('file_server'))
CONF.register_cli_opt(cfg.StrOpt('data_dir', default='./'))
CONF.register_cli_opt(cfg.StrOpt('murano_metadata_url'))
CONF.register_opt(cfg.IntOpt('max_environments', default=20))

162
muranoconductor/metadata.py Normal file
View File

@ -0,0 +1,162 @@
# Copyright (c) 2013 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 sys
import tarfile
import shutil
import tempfile
import hashlib
from glob import glob
from metadataclient.common.exceptions import CommunicationError
from muranoconductor import config
from metadataclient.v1.client import Client
import os
from openstack.common import log as logging
CHUNK_SIZE = 1 << 20 # 1MB
log = logging.getLogger(__name__)
CONF = config.CONF
class MetadataException(BaseException):
# Inherited not from Exception in purpose:
# On this exception ack message would not be sent
pass
def _unpack_data_archive(task_id, hash):
archive_name = hash + '.tar.gz'
if not tarfile.is_tarfile(archive_name):
raise MetadataException('Received invalid file {0} from Metadata '
'Repository'.format(hash))
dst_dir = task_id
if not os.path.exists(dst_dir):
os.mkdir(dst_dir)
with tarfile.open(archive_name, 'r:gz') as tar:
tar.extractall(path=dst_dir)
return dst_dir
def get_endpoint():
endpoint = CONF.murano_metadata_url
if not endpoint:
#TODO: add keystone catalog lookup
pass
return endpoint
def metadataclient(token_id):
endpoint = get_endpoint()
return Client(endpoint=endpoint, token=token_id)
def get_metadata(task_id, token_id):
hash = _check_existing_hash()
try:
log.debug('Retrieving metadata from Murano Metadata Repository')
resp, body_iter = metadataclient(token_id).\
metadata_client.get_conductor_data(hash)
except CommunicationError as e:
if hash:
log.warning('Metadata update failed: '
'Unable to connect Metadata Repository due to {0}. '
'Using existing version of metadata'.format(e))
else:
log.exception(e)
exc_type, exc_value, exc_traceback = sys.exc_info()
raise MetadataException('Unable to get data '
'from Metadata Repository due to {0}: '
'{1}'.format(exc_type.__name__, exc_value))
else:
if resp.status == 304:
log.debug('Metadata unmodified. Using existing archive.')
elif resp.status == 200:
with tempfile.NamedTemporaryFile(delete=False) as archive:
for chunk in body_iter:
archive.write(chunk)
hash = _get_hash(archive.name)
shutil.move(archive.name, hash + '.tar.gz')
else:
msg = 'Metadata update failed: ' \
'Got {0} status in response.'.format(resp.status)
if hash:
log.warning(msg + ' Using existing version of metadata.')
else:
raise MetadataException(msg)
return _unpack_data_archive(task_id, hash)
def release(folder):
log.debug('Deleting metadata folder {0}'.format(folder))
try:
shutil.rmtree(folder)
except Exception as e:
log.exception('Unable to delete folder {0} with '
'task metadata due to {1}'.format(folder, e))
def prepare(data_dir):
if not os.path.exists(data_dir):
os.makedirs(data_dir)
init_scripts_dst = os.path.join(data_dir,
os.path.basename(CONF.init_scripts_dir))
if not os.path.exists(init_scripts_dst):
shutil.copytree(CONF.init_scripts_dir, init_scripts_dst)
agent_config_dst = os.path.join(data_dir,
os.path.basename(CONF.agent_config_dir))
if not os.path.exists(agent_config_dst):
shutil.copytree(CONF.agent_config_dir, agent_config_dst)
os.chdir(data_dir)
def _get_hash(archive_path):
"""Calculate SHA1-hash of archive file.
SHA-1 take a bit more time than MD5 (see http://tinyurl.com/kpj5jy7),
but is more secure.
"""
if os.path.exists(archive_path):
sha1 = hashlib.sha1()
with open(archive_path) as f:
buf = f.read(CHUNK_SIZE)
while buf:
sha1.update(buf)
buf = f.read(CHUNK_SIZE)
hsum = sha1.hexdigest()
log.debug("Archive '{0}' has hash-sum {1}".format(archive_path, hsum))
return hsum
else:
log.info("Archive '{0}' doesn't exist, no hash to calculate".format(
archive_path))
return None
def _check_existing_hash():
hash_archives = glob('*.tar.gz')
if not hash_archives:
hash = None
else:
if len(hash_archives) > 1:
log.warning('There are to metadata archive. Deleting them both')
for item in hash_archives:
os.remove(item)
hash = None
else:
file_name, extension = hash_archives[0].split('.', 1)
hash = file_name
return hash

View File

@ -74,6 +74,7 @@ def _extract_v2_results(result_value, ok, errors):
def send_command(engine, context, body, template, service, unit,
mappings=None, result=None, error=None, timeout=None,
osVersion=None, **kwargs):
metadata_id = context['/metadata_id']
if not mappings:
mappings = {}
if osVersion:
@ -112,8 +113,14 @@ def send_command(engine, context, body, template, service, unit,
raise UnhandledAgentException(errors)
command_dispatcher.execute(
name='agent', template=template, mappings=mappings,
unit=unit, service=service, callback=callback, timeout=timeout)
name='agent',
template=template,
mappings=mappings,
unit=unit,
service=service,
callback=callback,
timeout=timeout,
metadata_id=metadata_id)
def _get_array_item(array, index):
@ -127,7 +134,7 @@ def _get_exception_info(data):
'message': _get_array_item(data, 1),
'command': _get_array_item(data, 2),
'details': _get_array_item(data, 3),
'timestamp': datetime.datetime.now().isoformat()
'timestamp': datetime.datetime.now().isoformat()
}
xml_code_engine.XmlCodeEngine.register_function(send_command, "send-command")

View File

@ -28,7 +28,8 @@ object_id = id
class Workflow(object):
def __init__(self, filename, data, command_dispatcher, config, reporter):
def __init__(self, filename, data, command_dispatcher,
config, reporter, metadata_id):
self._data = data
self._engine = xml_code_engine.XmlCodeEngine()
with open(filename) as xml:
@ -40,6 +41,7 @@ class Workflow(object):
# format: (rule-id, entity-id) => True for auto-reset bans,
# False for permanent bans
self._blacklist = {}
self._metadata_id = metadata_id
def execute(self):
context = function_context.Context()
@ -48,6 +50,7 @@ class Workflow(object):
context['/config'] = self._config
context['/reporter'] = self._reporter
context['/__blacklist'] = self._blacklist
context['/metadata_id'] = self._metadata_id
return self._engine.execute(context)
def prepare(self):

View File

@ -13,4 +13,4 @@ oslo.config>=1.2.0
deep
murano-common>=0.2.2
PyYAML>=3.1.0
murano-metadataclient==0.4.a13.gd65dfd2

View File

@ -31,8 +31,10 @@ class TestHeatExecutor(unittest.TestCase):
"$key": "$value"
}
}
self.metadata_id = 'b5bbea94023083e1ee06a52af5663b15c1fb1b7c'
self.mfs.add_entries({
'./data/templates/cf/test.template': json.dumps(template)})
'./{0}/templates/cf/test.template'.format(self.metadata_id):
json.dumps(template)})
def tearDown(self):
mockfs.restore_builtins()
@ -66,7 +68,8 @@ class TestHeatExecutor(unittest.TestCase):
arguments={
'arg1': 'arg1Value',
'arg2': 'arg2Value'},
callback=callback)
callback=callback,
metadata_id=self.metadata_id)
heat_mock().stacks.get().stack_status = 'CREATE_COMPLETE'
heat_mock().stacks.template = mock.MagicMock(
@ -107,7 +110,8 @@ class TestHeatExecutor(unittest.TestCase):
arguments={
'arg1': 'arg1Value',
'arg2': 'arg2Value'},
callback=callback)
callback=callback,
metadata_id=self.metadata_id)
get_mock = heat_mock().stacks.get()
get_mock.stack_name = 'stack'

View File

@ -36,16 +36,23 @@ class TestVmAgent(unittest.TestCase):
}],
"RebootOnCompletion": 0
}
self.metadata_id = 'a8571e3b1ba6b33f6c7dbe0f81217c5070377abe'
self.mfs.add_entries({
'./data/templates/agent/test.template':
'./a8571e3b1ba6b33f6c7dbe0f81217c5070377abe/'
'templates/agent/test.template':
json.dumps(self.template),
'./data/templates/agent/scripts/Get-DnsListeningIpAddress.ps1':
'./a8571e3b1ba6b33f6c7dbe0f81217c5070377abe/'
'templates/agent/scripts/Get-DnsListeningIpAddress.ps1':
'function GetDNSip(){\ntest\n}\n',
'./data/templates/agent/scripts/Join-Domain.ps1':
'./a8571e3b1ba6b33f6c7dbe0f81217c5070377abe/'
'templates/agent/scripts/Join-Domain.ps1':
'function JoinDomain(){\ntest\n}\n',
})
self.template_path = './data/templates/agent/test.template'
self.template_path = './a8571e3b1ba6b33f6c7dbe0f81217c5070377abe/' \
'templates/agent/test.template'
def test_script_encode(self):
stack = mock.MagicMock()

View File

@ -37,6 +37,7 @@ class TestWorkflow(unittest.TestCase):
self.mfs = mockfs.replace_builtins()
self.model = json.loads(load_sample('objectModel1.json'))
self.original_model = json.loads(load_sample('objectModel1.json'))
self.metadata_id = 'b5bbea94023083e1ee06a52af5663b15c1fb1b7c'
def tearDown(self):
mockfs.restore_builtins()
@ -45,7 +46,8 @@ class TestWorkflow(unittest.TestCase):
self.mfs.add_entries({'test': xml})
stub = mock.MagicMock()
stub.side_effect = RuntimeError
workflow = Workflow('test', self.model, stub, stub, stub)
workflow = Workflow('test', self.model, stub,
stub, stub, self.metadata_id)
workflow.execute()
def test_empty_workflow_leaves_object_model_unchanged(self):