diff --git a/molteniron/molteniron b/molteniron/molteniron index 2b2eb44..25410d8 100755 --- a/molteniron/molteniron +++ b/molteniron/molteniron @@ -118,10 +118,12 @@ class MoltenIron(object): return self.response_json @command - def add(self, subparsers=None): - """Generate a request to add a node to the MoltenIron database """ + def add_baremetal(self, subparsers=None): + """Generate a request to add a node to the MoltenIron database. + + All parameters are manditory.""" if subparsers is not None: - sp = subparsers.add_parser("add", + sp = subparsers.add_parser("add_baremetal", help="Add a node to the MoltenIron" " database.") sp.add_argument("name", @@ -154,7 +156,7 @@ class MoltenIron(object): type=int, help="Amount of disk (in GiB)" " that the node has") - sp.set_defaults(func=self.add) + sp.set_defaults(func=self.add_baremetal) return # Make a map of our arguments @@ -163,7 +165,72 @@ class MoltenIron(object): # But delete the class function pointer. json can't serialize it! del request['func'] - request['method'] = 'add' + request['method'] = 'add_baremetal' + + return request + + @command + def add_keyvalue_pairs(self, subparsers=None): + """Generate a request to add a node to the MoltenIron database. + + args are a list of key=value pairs.""" + if subparsers is not None: + sp = subparsers.add_parser("add_keyvalue_pairs", + help="Add a node to the MoltenIron" + " database.") + sp.add_argument("name", + help="Name of the baremetal node") + sp.add_argument("ipmi_ip", + help="IP for issuing IPMI commands to" + " this node") + sp.add_argument("allocation_pool", + help="Comma separated list of" + " IPs to be used in deployment") + sp.add_argument("args", + nargs=argparse.REMAINDER, + help="Architecture of the node") + sp.set_defaults(func=self.add_keyvalue_pairs) + return + + # Make a map of our arguments + request = vars(self.argv) + + # But delete the class function pointer. json can't serialize it! + del request['func'] + + request['method'] = 'add_keyvalue_pairs' + + return request + + @command + def add_json_blob(self, subparsers=None): + """Generate a request to add a node to the MoltenIron database. + + blob is a JSON encoded string.""" + if subparsers is not None: + sp = subparsers.add_parser("add_json_blob", + help="Add a node to the MoltenIron" + " database.") + sp.add_argument("name", + help="Name of the baremetal node") + sp.add_argument("ipmi_ip", + help="IP for issuing IPMI commands to" + " this node") + sp.add_argument("allocation_pool", + help="Comma separated list of" + " IPs to be used in deployment") + sp.add_argument("blob", + help="JSON encoded string") + sp.set_defaults(func=self.add_json_blob) + return + + # Make a map of our arguments + request = vars(self.argv) + + # But delete the class function pointer. json can't serialize it! + del request['func'] + + request['method'] = 'add_json_blob' return request @@ -262,6 +329,8 @@ class MoltenIron(object): help="Field name to set") sp.add_argument("value", help="Field value to set") + sp.add_argument("type", + help="Field Python type to set") sp.set_defaults(func=self.set_field) return @@ -303,6 +372,34 @@ class MoltenIron(object): return request + @command + def status_baremetal(self, subparsers=None): + """Return status """ + if subparsers is not None: + sp = subparsers.add_parser("status_baremetal", + help="Return a list of current" + " MoltenIron Node database" + " entries.") + sp.add_argument("-t", + "--type", + action="store", + type=str, + default="human", + dest="type", + help="Either human (the default) or csv") + sp.set_defaults(func=self.status_baremetal) + return + + # Make a map of our arguments + request = vars(self.argv) + + # But delete the class function pointer. json can't serialize it! + del request['func'] + + request['method'] = 'status_baremetal' + + return request + @command def delete_db(self, subparsers=None): """Delete all database entries""" diff --git a/molteniron/moltenirond.py b/molteniron/moltenirond.py index 868107c..8392a95 100755 --- a/molteniron/moltenirond.py +++ b/molteniron/moltenirond.py @@ -127,8 +127,27 @@ def MakeMoltenIronHandlerWithConf(conf): # Try to json-ify the request_string request = json.loads(request_string) method = request.pop('method') - if method == 'add': - response = database.addBMNode(request) + if method == 'add_baremetal': + node = {} + node['ipmi_user'] = request.pop('ipmi_user') + node['ipmi_password'] = request.pop('ipmi_password') + node['port_hwaddr'] = request.pop('port_hwaddr') + node['disk_gb'] = request.pop('disk_gb') + node['cpu_arch'] = request.pop('cpu_arch') + node['ram_mb'] = request.pop('ram_mb') + node['cpus'] = request.pop('cpus') + response = database.addBMNode(request, node) + elif method == 'add_keyvalue_pairs': + node = {} + + for elm in request["args"]: + idx = elm.find("=") + if idx > -1: + node[elm[:idx]] = elm[idx + 1:] + response = database.addBMNode(request, node) + elif method == 'add_json_blob': + node = json.loads(request.pop("blob")) + response = database.addBMNode(request, node) elif method == 'allocate': response = database.allocateBM(request['owner_name'], request['number_of_nodes']) @@ -140,9 +159,12 @@ def MakeMoltenIronHandlerWithConf(conf): elif method == 'set_field': response = database.set_field(request['id'], request['key'], - request['value']) + request['value'], + request['type']) elif method == 'status': response = database.status(request["type"]) + elif method == 'status_baremetal': + response = database.status_baremetal(request["type"]) elif method == 'delete_db': response = database.delete_db() database.close() @@ -169,13 +191,7 @@ class Nodes(declarative_base()): # id INTEGER NOT NULL AUTO_INCREMENT, #@TODO(hamzy) UNSIGNED # name VARCHAR(50), # ipmi_ip VARCHAR(50), - # ipmi_user VARCHAR(50), - # ipmi_password VARCHAR(50), - # port_hwaddr VARCHAR(50), - # cpu_arch VARCHAR(50), - # cpus INTEGER, - # ram_mb INTEGER, - # disk_gb INTEGER, + # blob VARCHAR(2000), # status VARCHAR(20), # provisioned VARCHAR(50), # timestamp TIMESTAMP NULL, @@ -185,13 +201,7 @@ class Nodes(declarative_base()): id = Column('id', Integer, primary_key=True) name = Column('name', String(50)) ipmi_ip = Column('ipmi_ip', String(50)) - ipmi_user = Column('ipmi_user', String(50)) - ipmi_password = Column('ipmi_password', String(50)) - port_hwaddr = Column('port_hwaddr', String(50)) - cpu_arch = Column('cpu_arch', String(50)) - cpus = Column('cpus', Integer) - ram_mb = Column('ram_mb', Integer) - disk_gb = Column('disk_gb', Integer) + blob = Column('blob', String(2000)) status = Column('status', String(20)) provisioned = Column('provisioned', String(50)) timestamp = Column('timestamp', TIMESTAMP) @@ -201,13 +211,7 @@ class Nodes(declarative_base()): id, name, ipmi_ip, - ipmi_user, - ipmi_password, - port_hwaddr, - cpu_arch, - cpus, - ram_mb, - disk_gb, + blob, status, provisioned, timestamp) @@ -222,13 +226,7 @@ class Nodes(declarative_base()): def __repr__(self): fmt = """""" @@ -236,13 +234,7 @@ timestamp='%s'/>""" return fmt % (self.name, self.ipmi_ip, - self.ipmi_user, - self.ipmi_password, - self.port_hwaddr, - self.cpu_arch, - self.cpus, - self.ram_mb, - self.disk_gb, + self.blob, self.status, self.provisioned, self.timestamp) @@ -323,26 +315,45 @@ class DataBase(object): self.create_metadata() - self.element_info = [ - # The following are returned from the query call + self.blob_status = { + "element_info": [ + # The following are returned from the query call - # field_name length special_fmt skip - ("id", 4, int, False), - ("name", 6, str, False), - ("ipmi_ip", 9, str, False), - ("ipmi_user", 11, str, False), - ("ipmi_password", 15, str, False), - ("port_hwaddr", 19, str, False), - ("cpu_arch", 10, str, False), - ("cpus", 6, int, False), - ("ram_mb", 8, int, False), - ("disk_gb", 9, int, False), - ("status", 8, str, False), - ("provisioned", 13, str, False), - # We add timeString - ("time", 14, float, False), - ] - self.setup_status() + # field_name length special_fmt skip + ("id", 4, int, False), + ("name", 6, str, False), + ("blob", 40, str, False), + ("status", 8, str, False), + ("provisioned", 13, str, False), + # We add timeString + ("time", 14, float, False), + ] + } + self.baremetal_status = { + "element_info": [ + # The following are returned from the query call + + # field_name length special_fmt skip + ("id", 4, int, False), + ("name", 6, str, False), + ("ipmi_ip", 9, str, False), + ("ipmi_user", 11, str, False), + ("ipmi_password", 15, str, False), + ("port_hwaddr", 19, str, False), + ("cpu_arch", 10, str, False), + ("cpus", 6, int, False), + ("ram_mb", 8, int, False), + ("disk_gb", 9, int, False), + ("status", 8, str, False), + ("provisioned", 13, str, False), + # We add timeString + ("time", 14, float, False), + ] + } + + # Pass map by reference but update our copy with the new information + self.baremetal_status = self.setup_status(**self.baremetal_status) + self.blob_status = self.setup_status(**self.blob_status) def create_engine(self): """Create the sqlalchemy database engine""" @@ -602,59 +613,57 @@ class DataBase(object): return {'status': 200} - def addBMNode(self, node): + def addBMNode(self, request, data_map): """Add a new node to molten iron. ex: - node = {u'name': u'test', - u'ipmi_user': u'user', - u'port_hwaddr': u'de:ad:be:ef:00:01', - u'disk_gb': 32, - u'cpu_arch': u'ppc64el', - u'ram_mb': 2048, - u'cpus': 8, - u'allocation_pool': u'0.0.0.1,0.0.0.2', - u'ipmi_password': u'password', - u'ipmi_ip': u'0.0.0.0'} + request = {u'name': u'test', + u'ipmi_ip': u'0.0.0.0', + u'status': u'', + u'provisioned': u'', + u'timestamp': u'', + u'allocation_pool': u'0.0.0.1,0.0.0.2'} + data_map = {u'ipmi_user': u'user', + u'ipmi_password': u'password', + u'port_hwaddr': u'de:ad:be:ef:00:01', + u'disk_gb': 32, + u'cpu_arch': u'ppc64el', + u'ram_mb': 2048, + u'cpus': 8} """ try: if DEBUG: - print("addBMNode: node = %s" % (node, )) + print("addBMNode: request = %s data_map = %s" + % (request, data_map, )) with self.session_scope() as session, \ self.connection_scope() as conn: # Check if it already exists query = session.query(Nodes) - query = query.filter_by(name=node['name']) + query = query.filter_by(name=request['name']) count = query.count() if count == 1: return {'status': 400, 'message': "Node already exists"} log(self.conf, - "adding node %(name)s ipmi_ip: %(ipmi_ip)s" % node) + "adding node %(name)s ipmi_ip: %(ipmi_ip)s" % request) # Add Node to database # Note: ID is always 0 as it is an auto-incrementing field stmt = insert(Nodes) - stmt = stmt.values(name=node['name']) - stmt = stmt.values(ipmi_ip=node['ipmi_ip']) - stmt = stmt.values(ipmi_user=node['ipmi_user']) - stmt = stmt.values(ipmi_password=node['ipmi_password']) - stmt = stmt.values(port_hwaddr=node['port_hwaddr']) - stmt = stmt.values(cpu_arch=node['cpu_arch']) - stmt = stmt.values(cpus=node['cpus']) - stmt = stmt.values(ram_mb=node['ram_mb']) - stmt = stmt.values(disk_gb=node['disk_gb']) + stmt = stmt.values(name=request['name']) + stmt = stmt.values(ipmi_ip=request['ipmi_ip']) + stmt = stmt.values(blob=json.dumps(data_map)) stmt = stmt.values(status='ready') - if 'status' in node: - stmt = stmt.values(status=node['status']) - if 'provisioned' in node: - stmt = stmt.values(provisioned=node['provisioned']) - if 'timestamp' in node: - timestamp_str = node['timestamp'] + if 'status' in request: + stmt = stmt.values(status=request['status']) + if 'provisioned' in request: + stmt = stmt.values(provisioned=request['provisioned']) + if 'timestamp' in request: + timestamp_str = request['timestamp'] if DEBUG: print("timestamp_str = %s" % (timestamp_str, )) if len(timestamp_str) != 0 and timestamp_str != "-1": @@ -672,14 +681,14 @@ class DataBase(object): session.close() session = self.get_session() - query = session.query(Nodes).filter_by(name=node['name']) + query = session.query(Nodes).filter_by(name=request['name']) new_node = query.one() # new_node is now a proper Node with an id # Add IPs to database # Note: id is always 0 as it is an auto-incrementing field - ips = node['allocation_pool'].split(',') + ips = request['allocation_pool'].split(',') for ip in ips: stmt = insert(IPs) stmt = stmt.values(node_id=new_node.id, ip=ip) @@ -877,10 +886,6 @@ class DataBase(object): def get_field(self, owner_name, field): """Return entries list with id, field for a given owner, field. """ - if not hasattr(Nodes, field): - return {'status': 400, - 'message': 'field %s does not exist' % (field,)} - results = [] try: @@ -900,7 +905,16 @@ class DataBase(object): for node in nodes: result = {'id': node.id} - result['field'] = getattr(node, field) + + try: + result["field"] = getattr(node, field) + except AttributeError: + blob = json.loads(node.blob) + if field in blob: + result["field"] = blob[field] + else: + msg = "field %s does not exist" % (field, ) + return {'status': 400, 'message': msg} results.append(result) @@ -914,28 +928,42 @@ class DataBase(object): return {'status': 200, 'result': results} - def set_field(self, node_id, key, value): + def set_field(self, node_id, key, value, python_type): """Given an identifying id, set specified key to the passed value. """ - if not hasattr(Nodes, key): - return {'status': 400, - 'message': 'field %s does not exist' % (key,)} - try: with self.session_scope() as session, \ self.connection_scope() as conn: + if python_type.upper().lower() == "string": + pass + elif python_type.upper().lower() == "int": + value = int(value) + else: + return {'status': 400, + 'message': 'Python type of %s is not supported!' + % (python_type, )} + query = session.query(Nodes) nodes = query.filter_by(id=node_id) if nodes.count() == 0: return {'status': 404, 'message': 'Node with id of %s does not exist!' - % node_id} + % (node_id, )} - nodes.one() + node = nodes.one() - kv = {key: value} + if hasattr(Nodes, key): + kv = {key: value} + else: + blob = json.loads(node.blob) + if key in blob: + blob[key] = value + kv = {"blob": json.dumps(blob)} + else: + return {'status': 400, + 'message': 'field %s does not exist' % (key,)} stmt = update(Nodes) stmt = stmt.where(Nodes.id == node_id) @@ -953,54 +981,63 @@ class DataBase(object): return {'status': 200} - def setup_status(self): + def setup_status(self, **status_map): """Setup the status formatting strings. Which depends on the skipped elements, lengths, and types. """ - self.result_separator = "+" - for (_, length, _, skip) in self.element_info: - if skip: - continue - self.result_separator += '-' * (1 + length + 1) + "+" + ei = status_map["element_info"] - self.description_line = "+" - for (field, length, _, skip) in self.element_info: + rs = "+" + for (_, length, _, skip) in ei: if skip: continue - self.description_line += (" " + - field + - ' ' * (length - len(field)) + - " +") + rs += '-' * (1 + length + 1) + "+" + + dl = "+" + for (field, length, _, skip) in ei: + if skip: + continue + dl += (" " + + field + + ' ' * (length - len(field)) + + " +") index = 0 - self.format_line = "|" - for (_, length, special_fmt, skip) in self.element_info: + fl = "|" + for (_, length, special_fmt, skip) in ei: if skip: continue if special_fmt is int: - self.format_line += " {%d:<%d} |" % (index, length) + fl += " {%d:<%d} |" % (index, length) elif special_fmt is str: - self.format_line += " {%d:%d} |" % (index, length) + fl += " {%d:%d} |" % (index, length) elif special_fmt is float: - self.format_line += " {%d:<%d.%d} |" \ - % (index, length, length - 2) + fl += " {%d:<%d.%d} |" \ + % (index, length, length - 2) index += 1 index = 0 - self.format_line_csv = "" - for (_, length, special_fmt, skip) in self.element_info: + flc = "" + for (_, length, special_fmt, skip) in ei: if skip: continue if special_fmt is int: - self.format_line_csv += "{%d}," % (index, ) + flc += "{%d}," % (index, ) elif special_fmt is str: - self.format_line_csv += "{%d}," % (index, ) + flc += "{%d}," % (index, ) elif special_fmt is float: - self.format_line_csv += "{%d}," % (index, ) + flc += "{%d}," % (index, ) index += 1 + status_map["result_separator"] = rs + status_map["description_line"] = dl + status_map["format_line"] = fl + status_map["format_line_csv"] = flc + + return status_map + def status(self, output_type): """Return a table that details the state of each bare metal node. @@ -1011,18 +1048,72 @@ class DataBase(object): output_type = output_type.upper().lower() if output_type == "csv": - return self.status_csv() + return self.status_csv(self.blob_status_elements, + **self.blob_status) elif output_type == "human": - return self.status_full() + return self.status_full(self.blob_status_elements, + **self.blob_status) else: return {'status': 400, 'message': "Unknown --type=%s" % (output_type, )} - def status_csv(self): + def status_baremetal(self, output_type): + """Return a table that details the state of each bare metal node. + + Currently this table is being created manually, there is probably a + better way to be doing this. + """ + + output_type = output_type.upper().lower() + + if output_type == "csv": + return self.status_csv(self.baremetal_status_elements, + **self.baremetal_status) + elif output_type == "human": + return self.status_full(self.baremetal_status_elements, + **self.baremetal_status) + else: + return {'status': 400, + 'message': "Unknown --type=%s" % (output_type, )} + + def blob_status_elements(self, node, timeString): + + blob = json.loads(node.blob) + + return (node.id, + node.name, + node.ipmi_ip, + blob, + node.status, + node.provisioned, + timeString) + + def baremetal_status_elements(self, node, timeString): + + blob = json.loads(node.blob) + + return (node.id, + node.name, + node.ipmi_ip, + blob["ipmi_user"], + blob["ipmi_password"], + blob["port_hwaddr"], + blob["cpu_arch"], + blob["cpus"], + blob["ram_mb"], + blob["disk_gb"], + node.status, + node.provisioned, + timeString) + + def status_csv(self, get_status_elements, **status_map): """Return a comma separated list of values""" result = "" + ei = status_map["element_info"] + flc = status_map["format_line_csv"] + try: with self.session_scope() as session: @@ -1030,36 +1121,30 @@ class DataBase(object): for node in query: - timeString = "" try: - if node.timestamp is not None: - elapsedTime = datetime.utcnow() - node.timestamp - timeString = str(elapsedTime) - except Exception: - pass - elements = (node.id, - node.name, - node.ipmi_ip, - node.ipmi_user, - node.ipmi_password, - node.port_hwaddr, - node.cpu_arch, - node.cpus, - node.ram_mb, - node.disk_gb, - node.status, - node.provisioned, - timeString) + timeString = "" + try: + if node.timestamp is not None: + et = datetime.utcnow() - node.timestamp + timeString = str(et) + except Exception: + pass - new_elements = [] - index = 0 - for (_, _, _, skip) in self.element_info: - if not skip: - new_elements.append(elements[index]) - index += 1 + elements = get_status_elements(node, timeString) - result += self.format_line_csv.format(*new_elements) + "\n" + new_elements = [] + index = 0 + for (_, _, _, skip) in ei: + if not skip: + new_elements.append(elements[index]) + index += 1 + + result += flc.format(*new_elements) + "\n" + + except KeyError: + + result += "blob missing baremetal fields\n" except Exception as e: @@ -1071,54 +1156,53 @@ class DataBase(object): return {'status': 200, 'result': result} - def status_full(self): + def status_full(self, get_status_elements, **status_map): """Return an ASCII table of the database entries""" result = "" + ei = status_map["element_info"] + rs = status_map["result_separator"] + dl = status_map["description_line"] + fl = status_map["format_line"] + try: with self.session_scope() as session: query = session.query(Nodes) - result += self.result_separator + "\n" - result += self.description_line + "\n" - result += self.result_separator + "\n" + result += rs + "\n" + result += dl + "\n" + result += rs + "\n" for node in query: - timeString = "" try: - if node.timestamp is not None: - elapsedTime = datetime.utcnow() - node.timestamp - timeString = str(elapsedTime) - except Exception: - pass - elements = (node.id, - node.name, - node.ipmi_ip, - node.ipmi_user, - node.ipmi_password, - node.port_hwaddr, - node.cpu_arch, - node.cpus, - node.ram_mb, - node.disk_gb, - node.status, - node.provisioned, - timeString) + timeString = "" + try: + if node.timestamp is not None: + et = datetime.utcnow() - node.timestamp + timeString = str(et) + except Exception: + pass - new_elements = [] - index = 0 - for (_, _, _, skip) in self.element_info: - if not skip: - new_elements.append(elements[index]) - index += 1 + elements = get_status_elements(node, timeString) - result += self.format_line.format(*new_elements) + "\n" + new_elements = [] + index = 0 + for (_, _, _, skip) in ei: + if not skip: + new_elements.append(elements[index]) + index += 1 - result += self.result_separator + "\n" + result += fl.format(*new_elements) + "\n" + + except KeyError: + + result += "blob missing baremetal fields\n" + + result += rs + "\n" except Exception as e: diff --git a/molteniron/tests/testAddBMNode.py b/molteniron/tests/testAddBMNode.py index c4ced62..d77f34c 100755 --- a/molteniron/tests/testAddBMNode.py +++ b/molteniron/tests/testAddBMNode.py @@ -53,87 +53,95 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "2f024600fc5ef6f7", - "port_hwaddr": "97: c3:b0: 47:0c:0d", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "6cf0957c985b2deb", - "port_hwaddr": "2d: 9e:3c:83:8a: be", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "cc777c10196db585", - "port_hwaddr": "47: b0:dc:d5: 82:d9", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "a700a2d789075276", - "port_hwaddr": "44: 94:1a: c7:8a:9f", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret['status'] == 400 assert ret['message'] == "Node already exists" - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret['status'] == 400 assert ret['message'] == "Node already exists" - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret['status'] == 400 assert ret['message'] == "Node already exists" diff --git a/molteniron/tests/testAllocateBM.py b/molteniron/tests/testAllocateBM.py index 955496e..01cc255 100755 --- a/molteniron/tests/testAllocateBM.py +++ b/molteniron/tests/testAllocateBM.py @@ -24,23 +24,51 @@ Tests the MoltenIron allocateBM command. from __future__ import print_function import argparse +import json from molteniron import moltenirond import os import sys import yaml -def compare_provisioned_nodes(lhs, rhs): - """Specially compares lhs against rhs.""" - lhs = lhs.copy() - rhs = rhs.copy() - rhs['provisioned'] = 'hamzy' - del lhs['status'] - del lhs['timestamp'] - del rhs['status'] - del rhs['timestamp'] - del lhs['id'] - assert lhs == rhs +def result_to_r(res): + """Takes a result and returns the request parameters.""" + + r = res.copy() + del r["blob"] + return r + + +def result_to_n(res): + """Takes a result and returns the node parameters.""" + + n = {} + if "blob" in res: + blob = json.loads(res["blob"]) + n["ipmi_user"] = blob["ipmi_user"] + n["ipmi_password"] = blob["ipmi_password"] + n["port_hwaddr"] = blob["port_hwaddr"] + n["cpu_arch"] = blob["cpu_arch"] + n["cpus"] = blob["cpus"] + n["ram_mb"] = blob["ram_mb"] + n["disk_gb"] = blob["disk_gb"] + return n + + +def compare_provisioned_nodes(lhs, rhs_r, rhs_n): + """Specially compares lhs against the combined rhs_r and rhs_n.""" + + rhs_r = rhs_r.copy() + lhs_r = result_to_r(lhs) + lhs_n = result_to_n(lhs) + rhs_r['provisioned'] = 'hamzy' + del lhs_r['status'] + del lhs_r['timestamp'] + del rhs_r['status'] + del rhs_r['timestamp'] + del lhs_r['id'] + assert lhs_r == rhs_r + assert lhs_n == rhs_n if __name__ == "__main__": @@ -67,79 +95,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "e05cc5f061426e34", - "port_hwaddr": "f8: de: 29:33:a4:ed", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "0614d63b6635ea3d", - "port_hwaddr": "4c: c5:da: 28:2c:2d", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "928b056134e4d770", - "port_hwaddr": "53: 76: c6:09:50:64", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "33f448a4fc176492", - "port_hwaddr": "85: e0: 73:e9:fc:ca", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -147,7 +183,7 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret["nodes"]) == 1 - compare_provisioned_nodes(ret["nodes"]["node_1"], node1) + compare_provisioned_nodes(ret["nodes"]["node_1"], request1, node1) database.close() del database @@ -159,16 +195,16 @@ if __name__ == "__main__": del database database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -176,8 +212,8 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret["nodes"]) == 2 - compare_provisioned_nodes(ret["nodes"]["node_1"], node1) - compare_provisioned_nodes(ret["nodes"]["node_2"], node2) + compare_provisioned_nodes(ret["nodes"]["node_1"], request1, node1) + compare_provisioned_nodes(ret["nodes"]["node_2"], request2, node2) database.close() del database @@ -189,16 +225,16 @@ if __name__ == "__main__": del database database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} diff --git a/molteniron/tests/testCull.py b/molteniron/tests/testCull.py index da410b1..f8e9b4a 100755 --- a/molteniron/tests/testCull.py +++ b/molteniron/tests/testCull.py @@ -24,6 +24,7 @@ Tests the MoltenIron cull command. from __future__ import print_function import argparse +import json from molteniron import moltenirond import os import sys @@ -31,16 +32,42 @@ import time import yaml -def compare_culled_nodes(lhs, rhs): +def result_to_r(res): + """Takes a result and returns the request parameters.""" + + r = res.copy() + del r["blob"] + return r + + +def result_to_n(res): + """Takes a result and returns the node parameters.""" + + n = {} + if "blob" in res: + blob = json.loads(res["blob"]) + n["ipmi_user"] = blob["ipmi_user"] + n["ipmi_password"] = blob["ipmi_password"] + n["port_hwaddr"] = blob["port_hwaddr"] + n["cpu_arch"] = blob["cpu_arch"] + n["cpus"] = blob["cpus"] + n["ram_mb"] = blob["ram_mb"] + n["disk_gb"] = blob["disk_gb"] + return n + + +def compare_culled_nodes(lhs, rhs_r, rhs_n): """Specially compares lhs against rhs.""" - lhs = lhs.copy() - rhs = rhs.copy() - del rhs['allocation_pool'] + rhs_r = rhs_r.copy() + lhs_r = result_to_r(lhs) + lhs_n = result_to_n(lhs) + del rhs_r['allocation_pool'] # timestamp can be converted on the server - del lhs['timestamp'] - del rhs['timestamp'] - del lhs['id'] - assert lhs == rhs + del lhs_r['timestamp'] + del rhs_r['timestamp'] + del lhs_r['id'] + assert lhs_r == rhs_r + assert lhs_n == rhs_n if __name__ == "__main__": parser = argparse.ArgumentParser(description="Molteniron CLI tool") @@ -66,80 +93,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "34118fd3509621ba", - "port_hwaddr": "ff: 2c: e1:cc:8e:7c", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "fa2125690a95b43c", - "port_hwaddr": "f6: 58:13:02:64:59", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "-1", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "3aee014d56425a6c", - "port_hwaddr": "6e: d4:a5:ae: 13:55", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", - # NOTE: time() can return fractional values. Ex: 1460560140.47 "timestamp": str(time.time() - 1000.0), "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "254dd9fb34ddcac7", - "port_hwaddr": "a0: c9: 22:23:22:9d", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": str(time.time() - 2000.0), "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -148,8 +182,8 @@ if __name__ == "__main__": assert ret['status'] == 200 assert len(ret['nodes']) == 2 - compare_culled_nodes(ret['nodes']['node_3'], node3) - compare_culled_nodes(ret['nodes']['node_4'], node4) + compare_culled_nodes(ret['nodes']['node_3'], request3, node3) + compare_culled_nodes(ret['nodes']['node_4'], request4, node4) database.close() del database @@ -161,16 +195,16 @@ if __name__ == "__main__": del database database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -179,7 +213,7 @@ if __name__ == "__main__": assert ret['status'] == 200 assert len(ret['nodes']) == 1 - compare_culled_nodes(ret['nodes']['node_4'], node4) + compare_culled_nodes(ret['nodes']['node_4'], request4, node4) database.close() del database @@ -191,16 +225,16 @@ if __name__ == "__main__": del database database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} diff --git a/molteniron/tests/testDeallocateBM.py b/molteniron/tests/testDeallocateBM.py index 0c11723..57470a7 100755 --- a/molteniron/tests/testDeallocateBM.py +++ b/molteniron/tests/testDeallocateBM.py @@ -24,23 +24,52 @@ Tests the MoltenIron deallocateBM command. from __future__ import print_function import argparse +import json from molteniron import moltenirond import os import sys import yaml -def compare_provisioned_nodes(lhs, rhs): - """Specially compares lhs against rhs.""" - lhs = lhs.copy() - rhs = rhs.copy() - rhs['provisioned'] = 'hamzy' - del lhs['status'] - del lhs['timestamp'] - del rhs['status'] - del rhs['timestamp'] - del lhs['id'] - assert lhs == rhs +def result_to_r(res): + """Takes a result and returns the request parameters.""" + + r = res.copy() + del r["blob"] + return r + + +def result_to_n(res): + """Takes a result and returns the node parameters.""" + + n = {} + if "blob" in res: + blob = json.loads(res["blob"]) + n["ipmi_user"] = blob["ipmi_user"] + n["ipmi_password"] = blob["ipmi_password"] + n["port_hwaddr"] = blob["port_hwaddr"] + n["cpu_arch"] = blob["cpu_arch"] + n["cpus"] = blob["cpus"] + n["ram_mb"] = blob["ram_mb"] + n["disk_gb"] = blob["disk_gb"] + return n + + +def compare_provisioned_nodes(lhs, rhs_r, rhs_n): + """Specially compares lhs against the combined rhs_r and rhs_n.""" + + rhs_r = rhs_r.copy() + lhs_r = result_to_r(lhs) + lhs_n = result_to_n(lhs) + rhs_r['provisioned'] = 'hamzy' + del lhs_r['status'] + del lhs_r['timestamp'] + del rhs_r['status'] + del rhs_r['timestamp'] + del lhs_r['id'] + assert lhs_r == rhs_r + assert lhs_n == rhs_n + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Molteniron CLI tool") @@ -66,79 +95,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "16f6954d347c4de2", - "port_hwaddr": "28: 5a: e7:e3:fe:75", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "3a23241cfa516699", - "port_hwaddr": "7d: 0a: e5:b9:41:9b", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "4f7e47c57f27ec55", - "port_hwaddr": "5a: e8: 11:e9:11:a2", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "aeff165ded2c2f9f", - "port_hwaddr": "4d: 18:82: dc:2c:d6", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -146,10 +183,12 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret["nodes"]) == 1 - compare_provisioned_nodes(ret["nodes"]["node_1"], node1) + compare_provisioned_nodes(ret["nodes"]["node_1"], request1, node1) session = database.get_session() - n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one() + n1 = session.query(moltenirond.Nodes) + n1 = n1.filter_by(name=request1["name"]) + n1 = n1.one() session.close() ret = database.deallocateBM(n1.id) print(ret) @@ -165,16 +204,16 @@ if __name__ == "__main__": del database database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -182,10 +221,12 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret["nodes"]) == 1 - compare_provisioned_nodes(ret["nodes"]["node_1"], node1) + compare_provisioned_nodes(ret["nodes"]["node_1"], request1, node1) session = database.get_session() - n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one() + n1 = session.query(moltenirond.Nodes) + n1 = n1.filter_by(name=request1["name"]) + n1 = n1.one() session.close() ret = database.deallocateBM(n1.ipmi_ip) print(ret) diff --git a/molteniron/tests/testDeallocateOwner.py b/molteniron/tests/testDeallocateOwner.py index af189ea..5db1213 100755 --- a/molteniron/tests/testDeallocateOwner.py +++ b/molteniron/tests/testDeallocateOwner.py @@ -24,23 +24,52 @@ Tests the MoltenIron deallocateOwner command. from __future__ import print_function import argparse +import json from molteniron import moltenirond import os import sys import yaml -def compare_provisioned_nodes(lhs, rhs): - """Specially compares lhs against rhs.""" - lhs = lhs.copy() - rhs = rhs.copy() - rhs['provisioned'] = 'hamzy' - del lhs['status'] - del lhs['timestamp'] - del rhs['status'] - del rhs['timestamp'] - del lhs['id'] - assert lhs == rhs +def result_to_r(res): + """Takes a result and returns the request parameters.""" + + r = res.copy() + del r["blob"] + return r + + +def result_to_n(res): + """Takes a result and returns the node parameters.""" + + n = {} + if "blob" in res: + blob = json.loads(res["blob"]) + n["ipmi_user"] = blob["ipmi_user"] + n["ipmi_password"] = blob["ipmi_password"] + n["port_hwaddr"] = blob["port_hwaddr"] + n["cpu_arch"] = blob["cpu_arch"] + n["cpus"] = blob["cpus"] + n["ram_mb"] = blob["ram_mb"] + n["disk_gb"] = blob["disk_gb"] + return n + + +def compare_provisioned_nodes(lhs, rhs_r, rhs_n): + """Specially compares lhs against the combined rhs_r and rhs_n.""" + + rhs_r = rhs_r.copy() + lhs_r = result_to_r(lhs) + lhs_n = result_to_n(lhs) + rhs_r['provisioned'] = 'hamzy' + del lhs_r['status'] + del lhs_r['timestamp'] + del rhs_r['status'] + del rhs_r['timestamp'] + del lhs_r['id'] + assert lhs_r == rhs_r + assert lhs_n == rhs_n + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Molteniron CLI tool") @@ -66,79 +95,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "f367d07be07d6358", - "port_hwaddr": "6d: 9a:78: f3:ed:3a", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "1c6a27307f8fe79d", - "port_hwaddr": "16: 23: e8:07:b4:a9", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "1766d597a024dd8d", - "port_hwaddr": "12: 33:9f:04:07:9b", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "7c55be8b4ef42869", - "port_hwaddr": "c2: 31: e9:8a:75:96", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -146,7 +183,7 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret["nodes"]) == 1 - compare_provisioned_nodes(ret["nodes"]["node_1"], node1) + compare_provisioned_nodes(ret["nodes"]["node_1"], request1, node1) ret = database.deallocateOwner("hamzy") print(ret) diff --git a/molteniron/tests/testDoClean.py b/molteniron/tests/testDoClean.py index a4d5471..b581cfb 100755 --- a/molteniron/tests/testDoClean.py +++ b/molteniron/tests/testDoClean.py @@ -54,79 +54,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "e23af1e52896cf02", - "port_hwaddr": "5d: 7e:05: dd:fe:65", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "57212373db56c76a", - "port_hwaddr": "7e: 41:89: e1:28:03", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "c2f4b0bfa31fe9de", - "port_hwaddr": "4f: a7: 48:59:6a:a7", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "f99d122fc129c1dd", - "port_hwaddr": "a2: 0d: bc:ca:c5:a5", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} diff --git a/molteniron/tests/testGetField.py b/molteniron/tests/testGetField.py index 2038a62..a1bcae3 100755 --- a/molteniron/tests/testGetField.py +++ b/molteniron/tests/testGetField.py @@ -54,79 +54,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "7db1486ac9ea6533", - "port_hwaddr": "ca: 2c: ab:88:47:b0", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "hamzy", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "c3f8e3f3407e880b", - "port_hwaddr": "90: 24:5c: d5:0e:b3", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "mjturek", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "1bcbf739c7108291", - "port_hwaddr": "9c: 6b:1b:31: a5:2d", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", - "ipmi_password": "0c200c858ac46280", - "port_hwaddr": "64: 49:12: c6:3f:bd", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "mjturek", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -143,7 +151,11 @@ if __name__ == "__main__": assert ret['result'][0]['field'] == node2["port_hwaddr"] assert ret['result'][1]['field'] == node4["port_hwaddr"] - ret = database.get_field("mmedvede", "candy") + ret = database.get_field("mmedvede", "cpus") + print(ret) + assert ret == {'status': 404, 'message': 'mmedvede does not own any nodes'} + + ret = database.get_field("hamzy", "candy") print(ret) assert ret == {'status': 400, 'message': 'field candy does not exist'} diff --git a/molteniron/tests/testGetIps.py b/molteniron/tests/testGetIps.py index 2bdbf86..5f464c5 100755 --- a/molteniron/tests/testGetIps.py +++ b/molteniron/tests/testGetIps.py @@ -54,79 +54,87 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "1aa328d7767653ad", - "port_hwaddr": "17: e7:f1:ab:a5: 9f", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "hamzy", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "84b9d9ceb866f612", - "port_hwaddr": "0b: f1: 9c:9d:a6:eb", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "mjturek", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "ba60285a1fd69800", - "port_hwaddr": "da: e0: 86:2a:80:9c", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", - "ipmi_password": "7810c66057ef4f2d", - "port_hwaddr": "d6: bc:ca: 83:95:e7", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "mjturek", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} @@ -134,13 +142,13 @@ if __name__ == "__main__": print(ret) assert ret['status'] == 200 assert len(ret['ips']) == 1 - assert ret['ips'] == [node1["ipmi_ip"]] + assert ret['ips'] == [request1["ipmi_ip"]] ret = database.get_ips("mjturek") print(ret) assert ret['status'] == 200 assert len(ret['ips']) == 2 - assert ret['ips'] == [node2["ipmi_ip"], node4["ipmi_ip"]] + assert ret['ips'] == [request2["ipmi_ip"], request4["ipmi_ip"]] database.close() del database diff --git a/molteniron/tests/testRemoveBMNode.py b/molteniron/tests/testRemoveBMNode.py index d30a57c..122dba5 100755 --- a/molteniron/tests/testRemoveBMNode.py +++ b/molteniron/tests/testRemoveBMNode.py @@ -54,84 +54,94 @@ if __name__ == "__main__": with open(yaml_file, "r") as fobj: conf = yaml.load(fobj) - node1 = { + request1 = { "name": "pkvmci816", "ipmi_ip": "10.228.219.134", - "ipmi_user": "user", - "ipmi_password": "2703f5fee17f2073", - "port_hwaddr": "b1: 71: dd:02:9e:20", - "cpu_arch": "ppc64el", - "cpus": 20, - "ram_mb": 51000, - "disk_gb": 500, "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.10,10.228.112.11" } - node2 = { - "name": "pkvmci818", - "ipmi_ip": "10.228.219.133", + node1 = { "ipmi_user": "user", - "ipmi_password": "c3f06ff4b798a4ea", - "port_hwaddr": "88: 6e:9e: fa:65:d8", + "ipmi_password": "e05cc5f061426e34", + "port_hwaddr": "f8:de:29:33:a4:ed", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request2 = { + "name": "pkvmci818", + "ipmi_ip": "10.228.219.133", "status": "ready", "provisioned": "", "timestamp": "", "allocation_pool": "10.228.112.8,10.228.112.9" } - node3 = { - "name": "pkvmci851", - "ipmi_ip": "10.228.118.129", + node2 = { "ipmi_user": "user", - "ipmi_password": "2885d1af50781461", - "port_hwaddr": "a2: a2: 64:79:6b:69", + "ipmi_password": "0614d63b6635ea3d", + "port_hwaddr": "4c:c5:da:28:2c:2d", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request3 = { + "name": "pkvmci851", + "ipmi_ip": "10.228.118.129", "status": "used", "provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f", "timestamp": "1460489832", "allocation_pool": "10.228.112.12,10.228.112.13" } - node4 = { - "name": "pkvmci853", - "ipmi_ip": "10.228.118.133", + node3 = { "ipmi_user": "user", - "ipmi_password": "3e374dc88ca43b4f", - "port_hwaddr": "50: 4a:56:3c: e9:0f", + "ipmi_password": "928b056134e4d770", + "port_hwaddr": "53:76:c6:09:50:64", "cpu_arch": "ppc64el", "cpus": 20, "ram_mb": 51000, - "disk_gb": 500, + "disk_gb": 500 + } + request4 = { + "name": "pkvmci853", + "ipmi_ip": "10.228.118.133", "status": "used", "provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d", "timestamp": "1460491566", "allocation_pool": "10.228.112.14,10.228.112.15" } + node4 = { + "ipmi_user": "user", + "ipmi_password": "33f448a4fc176492", + "port_hwaddr": "85:e0:73:e9:fc:ca", + "cpu_arch": "ppc64el", + "cpus": 20, + "ram_mb": 51000, + "disk_gb": 500 + } # 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<----- database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY) - ret = database.addBMNode(node1) + ret = database.addBMNode(request1, node1) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node2) + ret = database.addBMNode(request2, node2) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node3) + ret = database.addBMNode(request3, node3) print(ret) assert ret == {'status': 200} - ret = database.addBMNode(node4) + ret = database.addBMNode(request4, node4) print(ret) assert ret == {'status': 200} session = database.get_session() - n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one() + n1 = session.query(moltenirond.Nodes) + n1 = n1.filter_by(name=request1["name"]) + n1 = n1.one() session.close() ret = database.removeBMNode(n1.id, False) print(ret) diff --git a/tox.ini b/tox.ini index 7f87f58..c944b00 100644 --- a/tox.ini +++ b/tox.ini @@ -28,7 +28,32 @@ commands = mkdir -p testenv/var/run/ delete_db molteniron \ --conf-dir=testenv/etc/molteniron/ \ - add test 10.1.2.1 user password 10.1.2.3,10.1.2.4 de:ad:be:ef:00:01 ppc64el 8 2048 32 + add_baremetal test1 10.1.2.1 user password 10.1.2.3,10.1.2.4 de:ad:be:ef:00:01 ppc64el 8 2048 32 + molteniron \ + --conf-dir=testenv/etc/molteniron/ \ + add_keyvalue_pairs test2 \ + 10.1.2.2 \ + 10.1.2.5,10.1.2.6 \ + 'ipmi_user="user"' \ + 'ipmi_password="password"' \ + 'port_hwaddr="de:ad:be:ef:00:01"' \ + 'cpu_arch=ppc64el' \ + 'cpus=8' \ + 'ram_mb=2048' \ + 'disk_gb=32' +# @BUG - tox is broken +# passing in '{"ipmi_user": "user"}' results in: +# tox.ConfigError: ConfigError: No support for the "ipmi_user" substitution type +# and escaping the curly braces '\{"ipmi_user": "user"\}' +# mentioned in http://tox.readthedocs.io/en/latest/config.html#substitutions +# passes in '\\{"ipmi_user": "user"\\}' which breaks json.loads() +# ValueError: No JSON object could be decoded +# molteniron \ +# --conf-dir=testenv/etc/molteniron/ \ +# add_json_blob test3 \ +# 10.1.2.3 \ +# 10.1.2.7,10.1.2.8 \ +# '{"ipmi_user": "user", "ipmi_password": "password", "port_hwaddr": "de:ad:be:ef:00:01", "cpu_arch": "ppc64el", "cpus": 8, "ram_mb": 2048, "disk_gb": 32''}' molteniron \ --conf-dir=testenv/etc/molteniron/ \ allocate hamzy 1