added state option for creating instances

Change-Id: I92d6258d554e9a651d6e3f34872c77d7506095f7
diff --git a/nova/_modules/novang.py b/nova/_modules/novang.py
index 018e41e..bfd30a7 100644
--- a/nova/_modules/novang.py
+++ b/nova/_modules/novang.py
@@ -34,7 +34,7 @@
 __opts__ = {}
 
 
-def _auth(profile=None):
+def _auth(profile=None, tenant_name=None):
     '''
     Set up nova credentials
     '''
@@ -42,7 +42,10 @@
         credentials = __salt__['config.option'](profile)
         user = credentials['keystone.user']
         password = credentials['keystone.password']
-        tenant = credentials['keystone.tenant']
+        if tenant_name:
+            tenant = tenant_name
+        else:
+            tenant = credentials['keystone.tenant']
         auth_url = credentials['keystone.auth_url']
         region_name = credentials.get('keystone.region_name', None)
         api_key = credentials.get('keystone.api_key', None)
@@ -121,7 +124,51 @@
     nt_ks = conn.compute_conn
     item = nt_ks.quotas.update(tenant_id, **quota_argument)
     return item
+def server_list(profile=None, tenant_name=None):
+    '''
+    Return list of active servers
+    CLI Example:
+    .. code-block:: bash
+        salt '*' nova.server_list
+    '''
+    conn = _auth(profile, tenant_name)
+    return conn.server_list()
 
+def secgroup_list(profile=None, tenant_name=None):
+    '''
+    Return a list of available security groups (nova items-list)
+    CLI Example:
+    .. code-block:: bash
+        salt '*' nova.secgroup_list
+    '''
+    conn = _auth(profile, tenant_name)
+    return conn.secgroup_list()
 
-
-
+def boot(name, flavor_id=0, image_id=0, profile=None, tenant_name=None, timeout=300, **kwargs):
+    '''
+    Boot (create) a new instance
+    name
+        Name of the new instance (must be first)
+    flavor_id
+        Unique integer ID for the flavor
+    image_id
+        Unique integer ID for the image
+    timeout
+        How long to wait, after creating the instance, for the provider to
+        return information about it (default 300 seconds).
+        .. versionadded:: 2014.1.0
+    CLI Example:
+    .. code-block:: bash
+        salt '*' nova.boot myinstance flavor_id=4596 image_id=2
+    The flavor_id and image_id are obtained from nova.flavor_list and
+    nova.image_list
+    .. code-block:: bash
+        salt '*' nova.flavor_list
+        salt '*' nova.image_list
+    '''
+    #kwargs = {'nics': nics}
+    conn = _auth(profile, tenant_name)
+    return conn.boot(name, flavor_id, image_id, timeout, **kwargs)
+def network_show(name, profile=None):
+    conn = _auth(profile)
+    return conn.network_show(name)
diff --git a/nova/_states/novang.py b/nova/_states/novang.py
index 124faf4..76cf2f0 100644
--- a/nova/_states/novang.py
+++ b/nova/_states/novang.py
@@ -3,6 +3,7 @@
 Nova state that ensures that defined flavor is present
 '''
 import logging
+import collections
 from functools import wraps
 LOG = logging.getLogger(__name__)
 
@@ -11,8 +12,7 @@
     '''
     Only load if the nova module is in __salt__
     '''
-    return 'novang' if 'nova.flavor_list' in __salt__ else False   
-
+    return 'novang' if 'nova.flavor_list' in __salt__ else False
 
 def flavor_present(name, flavor_id=0, ram=0, disk=0, vcpus=1, profile=None):
     '''
@@ -33,7 +33,6 @@
         ret['changes']['Flavor'] = 'Created'
     return ret
 
-
 def quota_present(tenant_name, profile, name=None, **kwargs):
     '''
     Ensures that the nova quota exists
@@ -76,3 +75,61 @@
         changes_dict['comment'] = \
             '{0} {1} is in correct state'.format(resource, name)
     return changes_dict
+
+def instance_present(name, flavor, image, networks, security_groups=None, profile=None, tenant_name=None):
+    ret = {'name': name,
+           'changes': {},
+           'result': True,
+           'comment': 'Instance "{0}" already exists'.format(name)}
+    kwargs = {}
+    nics = []
+    existing_instances = __salt__['novang.server_list'](profile, tenant_name)
+    if name in existing_instances:
+        return ret
+    existing_flavors = __salt__['nova.flavor_list'](profile)
+    if flavor in existing_flavors:
+        flavor_id = existing_flavors[name]['id']
+    else:
+        return {'name': name,
+                'changes': {},
+                'result': False,
+                'comment': 'Flavor "{0}" doesn\'t exists'.format(flavor)}
+
+    existing_image = __salt__['nova.image_list'](image, profile)
+    if not existing_image:
+        return {'name': name,
+                'changes': {},
+                'result': False,
+                'comment': 'Image "{0}" doesn\'t exists'.format(image)}
+    else:
+        image_id = existing_image.get(image).get('id')
+    if security_groups is not None:
+        kwargs['security_groups'] = []
+        for secgroup in security_groups:
+            existing_secgroups = __salt__['novang.secgroup_list'](profile, tenant_name)
+            if not secgroup in existing_secgroups:
+                return {'name': name,
+                        'changes': {},
+                        'result': False,
+                        'comment': 'Security group "{0}" doesn\'t exists'.format(secgroup)}
+            else:
+                kwargs['security_groups'].append(secgroup)
+    for net in networks:
+        existing_network = __salt__['novang.network_show'](net.get('name'), profile)
+        if not existing_network:
+            return {'name': name,
+                    'changes': {},
+                    'result': False,
+                    'comment': 'Network "{0}" doesn\'t exists'.format(net.get(name))}
+        else:
+            network_id = existing_network.get('id')
+            if net.get('v4_fixed_ip') is not None:
+                nics.append({'net-id': network_id, 'v4-fixed-ip': net.get('v4_fixed_ip')})
+            else:
+                nics.append({'net-id': network_id})
+    kwargs['nics'] = nics
+    new_instance_id = __salt__['novang.boot'] (name, flavor_id, image_id, profile, tenant_name, **kwargs)
+    return {'name': name,
+            'changes': {},
+            'result': True,
+            'comment': 'Instance "{0}" was successfuly created'.format(name)}