Added *.pyo to .gitignore-common; minor typo fixed in openmano client
[osm/RO.git] / openmano
index b207d29..1e5f561 100755 (executable)
--- a/openmano
+++ b/openmano
@@ -28,8 +28,8 @@ openmano client used to interact with openmano-server (openmanod)
 '''
 __author__="Alfonso Tierno, Gerardo Garcia"
 __date__ ="$09-oct-2014 09:09:48$"
-__version__="0.4.3-r467"
-version_date="Mar 2016"
+__version__="0.4.7-r511"
+version_date="Oct 2016"
 
 from argcomplete.completers import FilesCompleter
 import os
@@ -59,8 +59,37 @@ class ThrowingArgumentParser(argparse.ArgumentParser):
 def config(args):
     print "OPENMANO_HOST: %s" %mano_host
     print "OPENMANO_PORT: %s" %mano_port
-    print "OPENMANO_TENANT: %s" %mano_tenant
-    print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
+    if args.n:
+        logger.debug("resolving tenant and datacenter names")
+        mano_tenant_id = "None"
+        mano_tenant_name = "None"
+        mano_datacenter_id = "None"
+        mano_datacenter_name = "None"
+        try:
+            mano_tenant_id = _get_item_uuid("tenants", mano_tenant)
+            URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, mano_tenant_id)
+            mano_response = requests.get(URLrequest)
+            logger.debug("openmano response: %s", mano_response.text )
+            content = mano_response.json()
+            mano_tenant_name = content["tenant"]["name"]
+            URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, mano_tenant_id, mano_datacenter)
+            mano_response = requests.get(URLrequest)
+            logger.debug("openmano response: %s", mano_response.text )
+            content = mano_response.json()
+            if "error" not in content:
+                mano_datacenter_id = content["datacenter"]["uuid"]
+                mano_datacenter_name = content["datacenter"]["name"]
+        except OpenmanoCLIError:
+            pass
+        print "OPENMANO_TENANT: %s" %mano_tenant
+        print "    Id: %s" %mano_tenant_id
+        print "    Name: %s" %mano_tenant_name 
+        print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
+        print "    Id: %s" %mano_datacenter_id
+        print "    Name: %s" %mano_datacenter_name 
+    else:
+        print "OPENMANO_TENANT: %s" %mano_tenant
+        print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
 
 def _print_verbose(mano_response, verbose_level=0):
     content = mano_response.json()
@@ -451,6 +480,8 @@ def scenario_deploy(args):
     args.file = None
     args.netmap_use = None
     args.netmap_create = None
+    args.keypair = None
+    args.keypair_auto = None
     return instance_create(args)
 
 #     #print "scenario-deploy",args
@@ -548,7 +579,7 @@ def instance_create(args):
     if args.scenario != None:
         scenario = args.scenario
     if not scenario:
-        print "you must provide an scenario in the file descriptor or with --scenario"
+        print "you must provide a scenario in the file descriptor or with --scenario"
         return -1
     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
     if args.netmap_use:
@@ -565,7 +596,9 @@ def instance_create(args):
                 net_datacenter = net_tuple[1].strip()
                 if net_scenario not in myInstance["instance"]["networks"]:
                     myInstance["instance"]["networks"][net_scenario] = {} 
-                myInstance["instance"]["networks"][net_scenario]["netmap-use"] = net_datacenter
+                if "sites" not in myInstance["instance"]["networks"][net_scenario]:
+                    myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
+                myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
     if args.netmap_create:
         if "networks" not in myInstance["instance"]:
             myInstance["instance"]["networks"] = {}
@@ -584,7 +617,52 @@ def instance_create(args):
                     return
                 if net_scenario not in myInstance["instance"]["networks"]:
                     myInstance["instance"]["networks"][net_scenario] = {} 
-                myInstance["instance"]["networks"][net_scenario]["netmap-create"] = net_datacenter
+                if "sites" not in myInstance["instance"]["networks"][net_scenario]:
+                    myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
+                myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
+    if args.keypair:
+        if "cloud-config" not in myInstance["instance"]:
+            myInstance["instance"]["cloud-config"] = {}
+        cloud_config = myInstance["instance"]["cloud-config"]
+        for key in args.keypair:
+            index = key.find(":")
+            if index<0:
+                if "key-pairs" not in cloud_config:
+                    cloud_config["key-pairs"] = []
+                cloud_config["key-pairs"].append(key)
+            else:
+                user = key[:index]
+                key_ = key[index+1:]
+                key_list = key_.split(",")
+                if "users" not in cloud_config:
+                    cloud_config["users"] = []
+                cloud_config["users"].append({"name": user, "key-pairs": key_list  })
+    if args.keypair_auto:
+        try:
+            keys=[]
+            home = os.getenv("HOME")
+            user = os.getenv("USER")
+            files = os.listdir(home+'/.ssh')
+            for file in files:
+                if file[-4:] == ".pub":
+                    with open(home+'/.ssh/'+file, 'r') as f:
+                        keys.append(f.read())
+            if not keys:
+                print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
+                return 1
+        except Exception as e:
+            print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
+            return 1
+        
+        if "cloud-config" not in myInstance["instance"]:
+            myInstance["instance"]["cloud-config"] = {}
+        cloud_config = myInstance["instance"]["cloud-config"]
+        if "key-pairs" not in cloud_config:
+            cloud_config["key-pairs"] = []
+        if user:
+            if "users" not in cloud_config:
+                cloud_config["users"] = []
+            cloud_config["users"].append({"name": user, "key-pairs": keys })                    
                         
     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
     logger.debug("openmano request: %s", payload_req)
@@ -664,12 +742,12 @@ def instance_scenario_list(args):
                 print "---------------------------------------"
                 print "Internal nets:"
                 for net in instance['nets']:
-                    if not net['external']:
+                    if net['created']:
                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
                 print "---------------------------------------"
                 print "External nets:"
                 for net in instance['nets']:
-                    if net['external']:
+                    if not net['created']:
                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
             print "---------------------------------------"
             print "VM instances:"
@@ -811,6 +889,8 @@ def datacenter_attach(args):
         datacenter_dict['vim_username'] = args.user
     if args.password != None:
         datacenter_dict['vim_password'] = args.password
+    if args.config!=None:
+        datacenter_dict["config"] = _load_file_or_yaml(args.config)
     payload_req = json.dumps( {"datacenter": datacenter_dict })
     
     #print payload_req
@@ -964,7 +1044,7 @@ def vim_action(args):
 
 def datacenter_net_action(args):
     if args.action == "net-update":
-        print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-upload' instead!!!"
+        print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
         print
         args.action = "netmap-delete"
         args.netmap = None
@@ -972,7 +1052,7 @@ def datacenter_net_action(args):
         r = datacenter_netmap_action(args)
         if r == 0:
             args.force = True
-            args.action = "netmap-upload"
+            args.action = "netmap-import"
             r = datacenter_netmap_action(args)
         return r
 
@@ -1018,7 +1098,7 @@ def datacenter_netmap_action(args):
         elif args.all: 
             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
         else:
-            print "you must a netmap name or the option --all"
+            print "you must specify a netmap name or the option --all"
             return 1
         if not args.force:
             r = raw_input(force_text)
@@ -1027,7 +1107,7 @@ def datacenter_netmap_action(args):
             else:
                 return 0
         mano_response = requests.delete(URLrequest, headers=headers_req)
-    elif args.action=="netmap-upload":
+    elif args.action=="netmap-import":
         if not args.force:
             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
             if  len(r)>0  and r[0].lower()=="y":
@@ -1114,13 +1194,14 @@ if __name__=="__main__":
     
     subparsers = main_parser.add_subparsers(help='commands')
     
-    config_parser = subparsers.add_parser('config', help="prints configuration values")
-    config_parser.set_defaults(func=config)
-
     parent_parser = argparse.ArgumentParser(add_help=False)
     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
 
+    config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
+    config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
+    config_parser.set_defaults(func=config)
+
     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
@@ -1179,6 +1260,8 @@ if __name__=="__main__":
     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
     instance_scenario_create_parser.add_argument("--netmap-use", action="append", type=str, dest="netmap_use", help="indicates a datacenter network to map a scenario network 'scenario-network=datacenter-network'. Can be used several times")
     instance_scenario_create_parser.add_argument("--netmap-create", action="append", type=str, dest="netmap_create", help="the scenario network must be created at datacenter 'scenario-network[=datacenter-network-name]' . Can be used several times")
+    instance_scenario_create_parser.add_argument("--keypair", action="append", type=str, dest="keypair", help="public key for ssh access. Format '[user:]key1[,key2...]'. Can be used several times")
+    instance_scenario_create_parser.add_argument("--keypair-auto", action="store_true", dest="keypair_auto", help="Inject the user ssh-keys found at $HOME/.ssh directory")
     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
     instance_scenario_create_parser.set_defaults(func=instance_create)
 
@@ -1254,6 +1337,7 @@ if __name__=="__main__":
     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
+    datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
     datacenter_attach_parser.set_defaults(func=datacenter_attach)
 
     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
@@ -1279,7 +1363,7 @@ if __name__=="__main__":
         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
 
 
-    action_dict={'netmap-upload': 'create network senario netmap base on the datacenter networks',
+    action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
                  'netmap-create': 'create a new network senario netmap',
                  'netmap-edit':   'edit name of a network senario netmap',
                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
@@ -1307,7 +1391,7 @@ if __name__=="__main__":
             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
-        if item=='netmap-upload':
+        if item=='netmap-import':
             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)