File: //usr/lib/python2.7/site-packages/salt/cloud/clouds/aliyun.py
# -*- coding: utf-8 -*-
'''
AliYun ECS Cloud Module
=======================
.. versionadded:: 2014.7.0
The Aliyun cloud module is used to control access to the aliyun ECS.
http://www.aliyun.com/
Use of this module requires the ``id`` and ``key`` parameter to be set.
Set up the cloud configuration at ``/etc/salt/cloud.providers`` or
``/etc/salt/cloud.providers.d/aliyun.conf``:
.. code-block:: yaml
my-aliyun-config:
# aliyun Access Key ID
id: wFGEwgregeqw3435gDger
# aliyun Access Key Secret
key: GDE43t43REGTrkilg43934t34qT43t4dgegerGEgg
location: cn-qingdao
driver: aliyun
:depends: requests
'''
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import time
import pprint
import logging
import hmac
import uuid
import sys
import base64
from hashlib import sha1
# Import Salt libs
from salt.ext.six.moves.urllib.parse import quote as _quote # pylint: disable=import-error,no-name-in-module
# Import salt cloud libs
import salt.utils.cloud
import salt.utils.data
import salt.utils.json
import salt.config as config
from salt.exceptions import (
SaltCloudNotFound,
SaltCloudSystemExit,
SaltCloudExecutionFailure,
SaltCloudExecutionTimeout
)
from salt.utils.stringutils import to_bytes
# Import 3rd-party libs
from salt.ext import six
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
# Get logging started
log = logging.getLogger(__name__)
ALIYUN_LOCATIONS = {
# 'us-west-2': 'ec2_us_west_oregon',
'cn-hangzhou': 'AliYun HangZhou Region',
'cn-beijing': 'AliYun BeiJing Region',
'cn-hongkong': 'AliYun HongKong Region',
'cn-qingdao': 'AliYun QingDao Region',
'cn-shanghai': 'AliYun ShangHai Region',
'cn-shenzhen': 'AliYun ShenZheng Region',
'ap-northeast-1': 'AliYun DongJing Region',
'ap-southeast-1': 'AliYun XinJiaPo Region',
'ap-southeast-2': 'AliYun XiNi Region',
'eu-central-1': 'EU FalaKeFu Region',
'me-east-1': 'ME DiBai Region',
'us-east-1': 'US FuJiNiYa Region',
'us-west-1': 'US GuiGu Region',
}
DEFAULT_LOCATION = 'cn-hangzhou'
DEFAULT_ALIYUN_API_VERSION = '2014-05-26'
__virtualname__ = 'aliyun'
# Only load in this module if the aliyun configurations are in place
def __virtual__():
'''
Check for aliyun configurations
'''
if get_configured_provider() is False:
return False
if get_dependencies() is False:
return False
return __virtualname__
def get_configured_provider():
'''
Return the first configured instance.
'''
return config.is_provider_configured(
__opts__,
__active_provider_name__ or __virtualname__,
('id', 'key')
)
def get_dependencies():
'''
Warn if dependencies aren't met.
'''
return config.check_driver_dependencies(
__virtualname__,
{'requests': HAS_REQUESTS}
)
def avail_locations(call=None):
'''
Return a dict of all available VM locations on the cloud provider with
relevant data
'''
if call == 'action':
raise SaltCloudSystemExit(
'The avail_locations function must be called with '
'-f or --function, or with the --list-locations option'
)
params = {'Action': 'DescribeRegions'}
items = query(params=params)
ret = {}
for region in items['Regions']['Region']:
ret[region['RegionId']] = {}
for item in region:
ret[region['RegionId']][item] = six.text_type(region[item])
return ret
def avail_images(kwargs=None, call=None):
'''
Return a list of the images that are on the provider
'''
if call == 'action':
raise SaltCloudSystemExit(
'The avail_images function must be called with '
'-f or --function, or with the --list-images option'
)
if not isinstance(kwargs, dict):
kwargs = {}
provider = get_configured_provider()
location = provider.get('location', DEFAULT_LOCATION)
if 'location' in kwargs:
location = kwargs['location']
params = {
'Action': 'DescribeImages',
'RegionId': location,
'PageSize': '100',
}
items = query(params=params)
ret = {}
for image in items['Images']['Image']:
ret[image['ImageId']] = {}
for item in image:
ret[image['ImageId']][item] = six.text_type(image[item])
return ret
def avail_sizes(call=None):
'''
Return a list of the image sizes that are on the provider
'''
if call == 'action':
raise SaltCloudSystemExit(
'The avail_sizes function must be called with '
'-f or --function, or with the --list-sizes option'
)
params = {'Action': 'DescribeInstanceTypes'}
items = query(params=params)
ret = {}
for image in items['InstanceTypes']['InstanceType']:
ret[image['InstanceTypeId']] = {}
for item in image:
ret[image['InstanceTypeId']][item] = six.text_type(image[item])
return ret
def get_location(vm_=None):
'''
Return the aliyun region to use, in this order:
- CLI parameter
- VM parameter
- Cloud profile setting
'''
return __opts__.get(
'location',
config.get_cloud_config_value(
'location',
vm_ or get_configured_provider(),
__opts__,
default=DEFAULT_LOCATION,
search_global=False
)
)
def list_availability_zones(call=None):
'''
List all availability zones in the current region
'''
ret = {}
params = {'Action': 'DescribeZones',
'RegionId': get_location()}
items = query(params)
for zone in items['Zones']['Zone']:
ret[zone['ZoneId']] = {}
for item in zone:
ret[zone['ZoneId']][item] = six.text_type(zone[item])
return ret
def list_nodes_min(call=None):
'''
Return a list of the VMs that are on the provider. Only a list of VM names,
and their state, is returned. This is the minimum amount of information
needed to check for existing VMs.
'''
if call == 'action':
raise SaltCloudSystemExit(
'The list_nodes_min function must be called with -f or --function.'
)
ret = {}
location = get_location()
params = {
'Action': 'DescribeInstanceStatus',
'RegionId': location,
}
nodes = query(params)
log.debug(
'Total %s instance found in Region %s',
nodes['TotalCount'], location
)
if 'Code' in nodes or nodes['TotalCount'] == 0:
return ret
for node in nodes['InstanceStatuses']['InstanceStatus']:
ret[node['InstanceId']] = {}
for item in node:
ret[node['InstanceId']][item] = node[item]
return ret
def list_nodes(call=None):
'''
Return a list of the VMs that are on the provider
'''
if call == 'action':
raise SaltCloudSystemExit(
'The list_nodes function must be called with -f or --function.'
)
nodes = list_nodes_full()
ret = {}
for instanceId in nodes:
node = nodes[instanceId]
ret[node['name']] = {
'id': node['id'],
'name': node['name'],
'public_ips': node['public_ips'],
'private_ips': node['private_ips'],
'size': node['size'],
'state': six.text_type(node['state']),
}
return ret
def list_nodes_full(call=None):
'''
Return a list of the VMs that are on the provider
'''
if call == 'action':
raise SaltCloudSystemExit(
'The list_nodes_full function must be called with -f '
'or --function.'
)
ret = {}
location = get_location()
params = {
'Action': 'DescribeInstanceStatus',
'RegionId': location,
'PageSize': '50'
}
result = query(params=params)
log.debug(
'Total %s instance found in Region %s',
result['TotalCount'], location
)
if 'Code' in result or result['TotalCount'] == 0:
return ret
# aliyun max 100 top instance in api
result_instancestatus = result['InstanceStatuses']['InstanceStatus']
if result['TotalCount'] > 50:
params['PageNumber'] = '2'
result = query(params=params)
result_instancestatus.update(result['InstanceStatuses']['InstanceStatus'])
for node in result_instancestatus:
instanceId = node.get('InstanceId', '')
params = {
'Action': 'DescribeInstanceAttribute',
'InstanceId': instanceId
}
items = query(params=params)
if 'Code' in items:
log.warning('Query instance:%s attribute failed', instanceId)
continue
name = items['InstanceName']
ret[name] = {
'id': items['InstanceId'],
'name': name,
'image': items['ImageId'],
'size': 'TODO',
'state': items['Status']
}
for item in items:
value = items[item]
if value is not None:
value = six.text_type(value)
if item == "PublicIpAddress":
ret[name]['public_ips'] = items[item]['IpAddress']
if item == "InnerIpAddress" and 'private_ips' not in ret[name]:
ret[name]['private_ips'] = items[item]['IpAddress']
if item == 'VpcAttributes':
vpc_ips = items[item]['PrivateIpAddress']['IpAddress']
if vpc_ips:
ret[name]['private_ips'] = vpc_ips
ret[name][item] = value
provider = __active_provider_name__ or 'aliyun'
if ':' in provider:
comps = provider.split(':')
provider = comps[0]
__opts__['update_cachedir'] = True
__utils__['cloud.cache_node_list'](ret, provider, __opts__)
return ret
def list_nodes_select(call=None):
'''
Return a list of the VMs that are on the provider, with select fields
'''
return salt.utils.cloud.list_nodes_select(
list_nodes_full('function'), __opts__['query.selection'], call,
)
def list_securitygroup(call=None):
'''
Return a list of security group
'''
if call == 'action':
raise SaltCloudSystemExit(
'The list_nodes function must be called with -f or --function.'
)
params = {
'Action': 'DescribeSecurityGroups',
'RegionId': get_location(),
'PageSize': '50',
}
result = query(params)
if 'Code' in result:
return {}
ret = {}
for sg in result['SecurityGroups']['SecurityGroup']:
ret[sg['SecurityGroupId']] = {}
for item in sg:
ret[sg['SecurityGroupId']][item] = sg[item]
return ret
def get_image(vm_):
'''
Return the image object to use
'''
images = avail_images()
vm_image = six.text_type(config.get_cloud_config_value(
'image', vm_, __opts__, search_global=False
))
if not vm_image:
raise SaltCloudNotFound('No image specified for this VM.')
if vm_image and six.text_type(vm_image) in images:
return images[vm_image]['ImageId']
raise SaltCloudNotFound(
'The specified image, \'{0}\', could not be found.'.format(vm_image)
)
def get_securitygroup(vm_):
'''
Return the security group
'''
sgs = list_securitygroup()
securitygroup = config.get_cloud_config_value(
'securitygroup', vm_, __opts__, search_global=False
)
if not securitygroup:
raise SaltCloudNotFound('No securitygroup ID specified for this VM.')
if securitygroup and six.text_type(securitygroup) in sgs:
return sgs[securitygroup]['SecurityGroupId']
raise SaltCloudNotFound(
'The specified security group, \'{0}\', could not be found.'.format(
securitygroup)
)
def get_size(vm_):
'''
Return the VM's size. Used by create_node().
'''
sizes = avail_sizes()
vm_size = six.text_type(config.get_cloud_config_value(
'size', vm_, __opts__, search_global=False
))
if not vm_size:
raise SaltCloudNotFound('No size specified for this VM.')
if vm_size and six.text_type(vm_size) in sizes:
return sizes[vm_size]['InstanceTypeId']
raise SaltCloudNotFound(
'The specified size, \'{0}\', could not be found.'.format(vm_size)
)
def __get_location(vm_):
'''
Return the VM's location
'''
locations = avail_locations()
vm_location = six.text_type(config.get_cloud_config_value(
'location', vm_, __opts__, search_global=False
))
if not vm_location:
raise SaltCloudNotFound('No location specified for this VM.')
if vm_location and six.text_type(vm_location) in locations:
return locations[vm_location]['RegionId']
raise SaltCloudNotFound(
'The specified location, \'{0}\', could not be found.'.format(
vm_location
)
)
def start(name, call=None):
'''
Start a node
CLI Examples:
.. code-block:: bash
salt-cloud -a start myinstance
'''
if call != 'action':
raise SaltCloudSystemExit(
'The stop action must be called with -a or --action.'
)
log.info('Starting node %s', name)
instanceId = _get_node(name)['InstanceId']
params = {'Action': 'StartInstance',
'InstanceId': instanceId}
result = query(params)
return result
def stop(name, force=False, call=None):
'''
Stop a node
CLI Examples:
.. code-block:: bash
salt-cloud -a stop myinstance
salt-cloud -a stop myinstance force=True
'''
if call != 'action':
raise SaltCloudSystemExit(
'The stop action must be called with -a or --action.'
)
log.info('Stopping node %s', name)
instanceId = _get_node(name)['InstanceId']
params = {
'Action': 'StopInstance',
'InstanceId': instanceId,
'ForceStop': six.text_type(force).lower()
}
result = query(params)
return result
def reboot(name, call=None):
'''
Reboot a node
CLI Examples:
.. code-block:: bash
salt-cloud -a reboot myinstance
'''
if call != 'action':
raise SaltCloudSystemExit(
'The stop action must be called with -a or --action.'
)
log.info('Rebooting node %s', name)
instance_id = _get_node(name)['InstanceId']
params = {'Action': 'RebootInstance',
'InstanceId': instance_id}
result = query(params)
return result
def create_node(kwargs):
'''
Convenience function to make the rest api call for node creation.
'''
if not isinstance(kwargs, dict):
kwargs = {}
# Required parameters
params = {
'Action': 'CreateInstance',
'InstanceType': kwargs.get('size_id', ''),
'RegionId': kwargs.get('region_id', DEFAULT_LOCATION),
'ImageId': kwargs.get('image_id', ''),
'SecurityGroupId': kwargs.get('securitygroup_id', ''),
'InstanceName': kwargs.get('name', ''),
}
# Optional parameters'
optional = [
'InstanceName', 'InternetChargeType',
'InternetMaxBandwidthIn', 'InternetMaxBandwidthOut',
'HostName', 'Password', 'SystemDisk.Category', 'VSwitchId'
# 'DataDisk.n.Size', 'DataDisk.n.Category', 'DataDisk.n.SnapshotId'
]
for item in optional:
if item in kwargs:
params.update({item: kwargs[item]})
# invoke web call
result = query(params)
return result['InstanceId']
def create(vm_):
'''
Create a single VM from a data dict
'''
try:
# Check for required profile parameters before sending any API calls.
if vm_['profile'] and config.is_profile_configured(__opts__,
__active_provider_name__ or 'aliyun',
vm_['profile'],
vm_=vm_) is False:
return False
except AttributeError:
pass
__utils__['cloud.fire_event'](
'event',
'starting create',
'salt/cloud/{0}/creating'.format(vm_['name']),
args=__utils__['cloud.filter_event']('creating', vm_, ['name', 'profile', 'provider', 'driver']),
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport']
)
log.info('Creating Cloud VM %s', vm_['name'])
kwargs = {
'name': vm_['name'],
'size_id': get_size(vm_),
'image_id': get_image(vm_),
'region_id': __get_location(vm_),
'securitygroup_id': get_securitygroup(vm_),
}
if 'vswitch_id' in vm_:
kwargs['VSwitchId'] = vm_['vswitch_id']
if 'internet_chargetype' in vm_:
kwargs['InternetChargeType'] = vm_['internet_chargetype']
if 'internet_maxbandwidthin' in vm_:
kwargs['InternetMaxBandwidthIn'] = six.text_type(vm_['internet_maxbandwidthin'])
if 'internet_maxbandwidthout' in vm_:
kwargs['InternetMaxBandwidthOut'] = six.text_type(vm_['internet_maxbandwidthOut'])
if 'hostname' in vm_:
kwargs['HostName'] = vm_['hostname']
if 'password' in vm_:
kwargs['Password'] = vm_['password']
if 'instance_name' in vm_:
kwargs['InstanceName'] = vm_['instance_name']
if 'systemdisk_category' in vm_:
kwargs['SystemDisk.Category'] = vm_['systemdisk_category']
__utils__['cloud.fire_event'](
'event',
'requesting instance',
'salt/cloud/{0}/requesting'.format(vm_['name']),
args=__utils__['cloud.filter_event']('requesting', kwargs, list(kwargs)),
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport']
)
try:
ret = create_node(kwargs)
except Exception as exc: # pylint: disable=broad-except
log.error(
'Error creating %s on Aliyun ECS\n\n'
'The following exception was thrown when trying to '
'run the initial deployment: %s',
vm_['name'], six.text_type(exc),
# Show the traceback if the debug logging level is enabled
exc_info_on_loglevel=logging.DEBUG
)
return False
# repair ip address error and start vm
time.sleep(8)
params = {'Action': 'StartInstance',
'InstanceId': ret}
query(params)
def __query_node_data(vm_name):
data = show_instance(vm_name, call='action')
if not data:
# Trigger an error in the wait_for_ip function
return False
if data.get('PublicIpAddress', None) is not None:
return data
try:
data = salt.utils.cloud.wait_for_ip(
__query_node_data,
update_args=(vm_['name'],),
timeout=config.get_cloud_config_value(
'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
interval=config.get_cloud_config_value(
'wait_for_ip_interval', vm_, __opts__, default=10),
)
except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
try:
# It might be already up, let's destroy it!
destroy(vm_['name'])
except SaltCloudSystemExit:
pass
finally:
raise SaltCloudSystemExit(six.text_type(exc))
if data['public_ips']:
ssh_ip = data['public_ips'][0]
elif data['private_ips']:
ssh_ip = data['private_ips'][0]
else:
log.info('No available ip:cant connect to salt')
return False
log.debug('VM %s is now running', ssh_ip)
vm_['ssh_host'] = ssh_ip
# The instance is booted and accessible, let's Salt it!
ret = __utils__['cloud.bootstrap'](vm_, __opts__)
ret.update(data)
log.info('Created Cloud VM \'%s\'', vm_['name'])
log.debug(
'\'%s\' VM creation details:\n%s',
vm_['name'], pprint.pformat(data)
)
__utils__['cloud.fire_event'](
'event',
'created instance',
'salt/cloud/{0}/created'.format(vm_['name']),
args=__utils__['cloud.filter_event']('created', vm_, ['name', 'profile', 'provider', 'driver']),
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport']
)
return ret
def _compute_signature(parameters, access_key_secret):
'''
Generate aliyun request signature
'''
def percent_encode(line):
if not isinstance(line, six.string_types):
return line
s = line
if sys.stdin.encoding is None:
s = line.decode().encode('utf8')
else:
s = line.decode(sys.stdin.encoding).encode('utf8')
res = _quote(s, '')
res = res.replace('+', '%20')
res = res.replace('*', '%2A')
res = res.replace('%7E', '~')
return res
sortedParameters = sorted(list(parameters.items()), key=lambda items: items[0])
canonicalizedQueryString = ''
for k, v in sortedParameters:
canonicalizedQueryString += '&' + percent_encode(k) \
+ '=' + percent_encode(v)
# All aliyun API only support GET method
stringToSign = 'GET&%2F&' + percent_encode(canonicalizedQueryString[1:])
h = hmac.new(to_bytes(access_key_secret + "&"), stringToSign, sha1)
signature = base64.encodestring(h.digest()).strip()
return signature
def query(params=None):
'''
Make a web call to aliyun ECS REST API
'''
path = 'https://ecs-cn-hangzhou.aliyuncs.com'
access_key_id = config.get_cloud_config_value(
'id', get_configured_provider(), __opts__, search_global=False
)
access_key_secret = config.get_cloud_config_value(
'key', get_configured_provider(), __opts__, search_global=False
)
timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
# public interface parameters
parameters = {
'Format': 'JSON',
'Version': DEFAULT_ALIYUN_API_VERSION,
'AccessKeyId': access_key_id,
'SignatureVersion': '1.0',
'SignatureMethod': 'HMAC-SHA1',
'SignatureNonce': six.text_type(uuid.uuid1()),
'TimeStamp': timestamp,
}
# include action or function parameters
if params:
parameters.update(params)
# Calculate the string for Signature
signature = _compute_signature(parameters, access_key_secret)
parameters['Signature'] = signature
request = requests.get(path, params=parameters, verify=True)
if request.status_code != 200:
raise SaltCloudSystemExit(
'An error occurred while querying aliyun ECS. HTTP Code: {0} '
'Error: \'{1}\''.format(
request.status_code,
request.text
)
)
log.debug(request.url)
content = request.text
result = salt.utils.json.loads(content)
if 'Code' in result:
raise SaltCloudSystemExit(
pprint.pformat(result.get('Message', {}))
)
return result
def script(vm_):
'''
Return the script deployment object
'''
deploy_script = salt.utils.cloud.os_script(
config.get_cloud_config_value('script', vm_, __opts__),
vm_,
__opts__,
salt.utils.cloud.salt_config_to_yaml(
salt.utils.cloud.minion_config(__opts__, vm_)
)
)
return deploy_script
def show_disk(name, call=None):
'''
Show the disk details of the instance
CLI Examples:
.. code-block:: bash
salt-cloud -a show_disk aliyun myinstance
'''
if call != 'action':
raise SaltCloudSystemExit(
'The show_disks action must be called with -a or --action.'
)
ret = {}
params = {
'Action': 'DescribeInstanceDisks',
'InstanceId': name
}
items = query(params=params)
for disk in items['Disks']['Disk']:
ret[disk['DiskId']] = {}
for item in disk:
ret[disk['DiskId']][item] = six.text_type(disk[item])
return ret
def list_monitor_data(kwargs=None, call=None):
'''
Get monitor data of the instance. If instance name is
missing, will show all the instance monitor data on the region.
CLI Examples:
.. code-block:: bash
salt-cloud -f list_monitor_data aliyun
salt-cloud -f list_monitor_data aliyun name=AY14051311071990225bd
'''
if call != 'function':
raise SaltCloudSystemExit(
'The list_monitor_data must be called with -f or --function.'
)
if not isinstance(kwargs, dict):
kwargs = {}
ret = {}
params = {
'Action': 'GetMonitorData',
'RegionId': get_location()
}
if 'name' in kwargs:
params['InstanceId'] = kwargs['name']
items = query(params=params)
monitorData = items['MonitorData']
for data in monitorData['InstanceMonitorData']:
ret[data['InstanceId']] = {}
for item in data:
ret[data['InstanceId']][item] = six.text_type(data[item])
return ret
def show_instance(name, call=None):
'''
Show the details from aliyun instance
'''
if call != 'action':
raise SaltCloudSystemExit(
'The show_instance action must be called with -a or --action.'
)
return _get_node(name)
def _get_node(name):
attempts = 5
while attempts >= 0:
try:
return list_nodes_full()[name]
except KeyError:
attempts -= 1
log.debug(
'Failed to get the data for node \'%s\'. Remaining '
'attempts: %s', name, attempts
)
# Just a little delay between attempts...
time.sleep(0.5)
raise SaltCloudNotFound(
'The specified instance {0} not found'.format(name)
)
def show_image(kwargs, call=None):
'''
Show the details from aliyun image
'''
if call != 'function':
raise SaltCloudSystemExit(
'The show_images function must be called with '
'-f or --function'
)
if not isinstance(kwargs, dict):
kwargs = {}
location = get_location()
if 'location' in kwargs:
location = kwargs['location']
params = {
'Action': 'DescribeImages',
'RegionId': location,
'ImageId': kwargs['image']
}
ret = {}
items = query(params=params)
# DescribeImages so far support input multi-image. And
# if not found certain image, the response will include
# blank image list other than 'not found' error message
if 'Code' in items or not items['Images']['Image']:
raise SaltCloudNotFound('The specified image could not be found.')
log.debug(
'Total %s image found in Region %s',
items['TotalCount'], location
)
for image in items['Images']['Image']:
ret[image['ImageId']] = {}
for item in image:
ret[image['ImageId']][item] = six.text_type(image[item])
return ret
def destroy(name, call=None):
'''
Destroy a node.
CLI Example:
.. code-block:: bash
salt-cloud -a destroy myinstance
salt-cloud -d myinstance
'''
if call == 'function':
raise SaltCloudSystemExit(
'The destroy action must be called with -d, --destroy, '
'-a or --action.'
)
__utils__['cloud.fire_event'](
'event',
'destroying instance',
'salt/cloud/{0}/destroying'.format(name),
args={'name': name},
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport']
)
instanceId = _get_node(name)['InstanceId']
# have to stop instance before del it
stop_params = {
'Action': 'StopInstance',
'InstanceId': instanceId
}
query(stop_params)
params = {
'Action': 'DeleteInstance',
'InstanceId': instanceId
}
node = query(params)
__utils__['cloud.fire_event'](
'event',
'destroyed instance',
'salt/cloud/{0}/destroyed'.format(name),
args={'name': name},
sock_dir=__opts__['sock_dir'],
transport=__opts__['transport']
)
return node