From 9b382805740e6f7ecd57a1b4568bd98470f7666e Mon Sep 17 00:00:00 2001 From: jc0b Date: Tue, 9 Jun 2020 14:53:11 +0200 Subject: rebasing --- mongodb/docker-compose.yml | 30 +++++++ mongodb/mongo-init-opendc-db.sh | 173 ++++++++++++++++++++++++++++++---------- mongodb/prefab.py | 110 +++++++++++++++++++++++++ mongodb/prefabs.py | 124 ++++++++++++++++++++++++++++ 4 files changed, 397 insertions(+), 40 deletions(-) create mode 100644 mongodb/docker-compose.yml create mode 100755 mongodb/prefab.py create mode 100755 mongodb/prefabs.py (limited to 'mongodb') diff --git a/mongodb/docker-compose.yml b/mongodb/docker-compose.yml new file mode 100644 index 00000000..0253cd7d --- /dev/null +++ b/mongodb/docker-compose.yml @@ -0,0 +1,30 @@ +version: "3" +services: + mongo: + build: + context: ./ + restart: on-failure + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: rootpassword + MONGO_INITDB_DATABASE: admin + OPENDC_DB: opendc + OPENDC_DB_USERNAME: opendc + OPENDC_DB_PASSWORD: opendcpassword + ports: + - 27017:27017 + #volumes: + # - mongo-volume:/data/db + + mongo-express: + image: mongo-express + restart: on-failure + ports: + - 8082:8081 + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: rootpassword + +volumes: + mongo-volume: + external: false \ No newline at end of file diff --git a/mongodb/mongo-init-opendc-db.sh b/mongodb/mongo-init-opendc-db.sh index ed33e955..965698e7 100644 --- a/mongodb/mongo-init-opendc-db.sh +++ b/mongodb/mongo-init-opendc-db.sh @@ -12,43 +12,136 @@ MONGO_ROOT_CMD="mongo $OPENDC_DB --host localhost --port 27017 -u $MONGO_INITDB_ #echo 'Creating opendc db schema...' MONGO_CMD="mongo $OPENDC_DB -u $OPENDC_DB_USERNAME -p $OPENDC_DB_PASSWORD --authenticationDatabase $OPENDC_DB" -$MONGO_CMD --eval 'db.createCollection("environments", { - validator: { - $jsonSchema: { - bsonType: "object", - required: ["name"], - properties: { - name: { - bsonType: "string", - description: "The name of the environment i.e. Production, or Compute Cluster" - }, - datacenters: { - bsonType: "object", - required: ["name, location, length, width, height"], - properties: { - name: { - bsonType: "string", - description: "The name of the datacenter i.e. eu-west-1, or Science Building" - }, - location: { - bsonType: "string", - description: "The location of the datacenter i.e. Frankfurt, or De Boelelaan 1105" - }, - length: { - bsonType: "double", - description: "The physical length of the datacenter, in centimetres" - }, - width: { - bsonType: "double", - description: "The physical width of the datacenter, in centimetres" - }, - height: { - bsonType: "double", - description: "The physical height of the datacenter, in centimetres" - } - } - } - } - } - } -});' \ No newline at end of file +$MONGO_CMD --eval 'db.createCollection("prefabs");' + +$MONGO_CMD --eval 'db.prefabs.insertOne( + { + "type": "rack", + "name": "test_rack3", + "size": 42, + "depth": 42, + "author": "Jacob Burley", + "visibility": "public", + "children": [ + { + "type": "switch", + "ports": 48, + "power_draw": 150, + "psus": 1, + "size": 1 + }, + { + "type": "chassis", + "size": 4, + "children": [ + { + "type": "mainboard", + "sockets": 1, + "dimm_slots": 4, + "nics": 1, + "pcie_slots": 2, + "children": [ + { + "type": "CPU", + "coreCount": 4, + "SMT": true, + "base_clk": 3.5, + "boost_clk": 3.9, + "brand": "Intel", + "SKU": "i7-3770K", + "socket": "LGA1155", + "TDP": 77 + }, + { + "type": "DDR3", + "capacity": 4096, + "memfreq": 1333, + "ecc": false + }, + { + "type": "DDR3", + "capacity": 4096, + "memfreq": 1333, + "ecc": false + }, + { + "type": "DDR3", + "capacity": 4096, + "memfreq": 1333, + "ecc": false + }, + { + "type": "DDR3", + "capacity": 4096, + "memfreq": 1333, + "ecc": false + }, + { + "type": "GPU", + "VRAM": 8192, + "coreCount": 2304, + "brand": "AMD", + "technologies": "OpenCL", + "pcie_gen": "3x16", + "tdp": 169, + "slots": 2 + } + ] + }, + { + "type": "PSU", + "wattage": 550, + "ac": true + }, + { + "type": "disk", + "size": 2000, + "interface": "SATA", + "media": "flash", + "form_factor": 2.5 + } + ] + } + ] + });' + +# $MONGO_CMD --eval 'db.createCollection("prefabs", { +# validator: { +# $jsonSchema: { +# bsonType: "object", +# required: ["name"], +# properties: { +# name: { +# bsonType: "string", +# description: "The name of the environment i.e. Production, or Compute Cluster" +# }, +# datacenters: { +# bsonType: "object", +# required: ["name, location, length, width, height"], +# properties: { +# name: { +# bsonType: "string", +# description: "The name of the datacenter i.e. eu-west-1, or Science Building" +# }, +# location: { +# bsonType: "string", +# description: "The location of the datacenter i.e. Frankfurt, or De Boelelaan 1105" +# }, +# length: { +# bsonType: "double", +# description: "The physical length of the datacenter, in centimetres" +# }, +# width: { +# bsonType: "double", +# description: "The physical width of the datacenter, in centimetres" +# }, +# height: { +# bsonType: "double", +# description: "The physical height of the datacenter, in centimetres" +# } +# } +# } +# } +# } +# } +# });' \ No newline at end of file diff --git a/mongodb/prefab.py b/mongodb/prefab.py new file mode 100755 index 00000000..1ce355fd --- /dev/null +++ b/mongodb/prefab.py @@ -0,0 +1,110 @@ +#!/Users/jacobburley/thesis-src/opendc/mongodb/opendc_testing/bin/python3 +#Change shebang to /usr/bin/python3 before using with docker +# encoding: utf-8 +""" +prefab + +CLI frontend for viewing, modifying and creating prefabs in OpenDC. + +""" +import sys +import prefabs + +def usage(): + print("Usage: prefab add : imports a prefab from YML or JSON") + print(" list: lists all (public) prefabs") + print(" export [json|yaml]: exports the specified prefab to the specified filetype (with JSON used by default)") + +def interactive(): #interactive CLI mode: recommended + print("OpenDC Prefab CLI") + running = True + while(exit): + print(">", end=" ") + try: + command = input() + command = command.split() + except EOFError as e: + print("exit") + print("bye!") + exit() + except KeyboardInterrupt as KI: + print("\nbye!") + exit() + if(len(command) >= 1): + if(command[0] == "exit"): + print("bye!") + exit() + elif(command[0] == "list"): # decrypt + prefabs.list() + elif(command[0] == "help"): # decrypt + usage() + elif(command[0] == "add"): + if(len(command) == 3): + prefabs.add(command[1], command[2]) + else: + prefabs.add(command[1], None) + elif(command[0] == "clone"): + if(len(command) == 3): + prefabs.clone(command[1], command[2]) + else: + prefabs.clone(command[1], None) + elif(command[0] == "export"): + #print(sys.argv[2]) + prefabs.export(command[1], "json") + elif(command[0] == "remove"): + print("WARNING: Doing so will permanently remove the specified prefab. \nThis action CANNOT be undone. Please type the name of the prefab to confirm deletion.") + confirm = input() + if confirm == command[1]: + prefabs.remove(command[1]) + print(f'Prefab {command[1]} has been removed.') + else: + print("Confirmation failed. The prefab has not been removed.") + else: + print("prefabs: try 'help' for more information\n") + else: + print("prefabs: try 'help' for more information\n") + + +def main(): + if(len(sys.argv) >= 2): + if(sys.argv[1] == "list"): # decrypt + prefabs.list() + exit() + #elif(sys.argv[1] == "-e"): # encrypt + # encrypt(sys.argv[2], sys.argv[3], sys.argv[4]) + #elif(sys.argv[1] == "-v"): # verify + # verify(sys.argv[2], sys.argv[3], sys.argv[4]) + elif(sys.argv[1] == "help"): # decrypt + usage() + exit() + elif(sys.argv[1] == "add"): + if(sys.argv[3]): + prefabs.add(sys.argv[2], sys.argv[3]) + else: + prefabs.add(sys.argv[2]) + exit() + elif(sys.argv[1] == "export"): + #print(sys.argv[2]) + prefabs.export(sys.argv[2], "json") + exit() + elif(sys.argv[1] == "remove"): + print("WARNING: Doing so will permanently remove the specified prefab. \nThis action CANNOT be undone. Please type the name of the prefab to confirm deletion.") + confirm = input() + if confirm == sys.argv[2]: + prefabs.remove(sys.argv[2]) + print(f'Prefab {sys.argv[2]} has been removed.') + else: + print("Confirmation failed. The prefab has not been removed.") + exit() + else: + print("prefabs: try 'prefabs help' for more information\n") + elif(len(sys.argv) == 1): + interactive() + + else: + # print "Incorrect number of arguments!\n" + print("prefabs: try 'prefabs help' for more information\n") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mongodb/prefabs.py b/mongodb/prefabs.py new file mode 100755 index 00000000..f6f46cbc --- /dev/null +++ b/mongodb/prefabs.py @@ -0,0 +1,124 @@ +#!/Users/jacobburley/thesis-src/opendc/mongodb/opendc_testing/bin/python3 +#Change shebang to /usr/bin/python3 before using with docker +# encoding: utf-8 +""" +prefabs + +Python Library for interacting with mongoDB prefabs collection. + +""" +import urllib.parse +import pprint +import sys +import os +import json +import re +import ujson +#import pyyaml + +from pymongo import MongoClient +from bson.json_util import loads, dumps, RELAXED_JSON_OPTIONS, CANONICAL_JSON_OPTIONS + +#mongodb_opendc_db = os.environ['OPENDC_DB'] +#mongodb_opendc_user = os.environ['OPENDC_DB_USERNAME'] +#mongodb_opendc_password = os.environ['OPENDC_DB_PASSWORD'] + +#if mongodb_opendc_db == None or mongodb_opendc_user == None or mongodb_opendc_password == None: +# print("One or more environment variables are not set correctly. \nYou may experience issues connecting to the mongodb database.") + +user = urllib.parse.quote_plus('opendc') #TODO: replace this with environment variable +password = urllib.parse.quote_plus('opendcpassword') #TODO: same as above +database = urllib.parse.quote_plus('opendc') + +client = MongoClient('mongodb://%s:%s@localhost/default_db?authSource=%s' % (user, password, database)) +opendcdb = client.opendc +prefabs_collection = opendcdb.prefabs + + +def add(prefab_file, name): + if(re.match(r"\w+(\\\ \w*)*\.json", prefab_file)): + try: + with open(prefab_file, "r") as json_file: + json_prefab = json.load(json_file) + #print(json_prefab) + if name != None: + json_prefab["name"] = name + try: + prefab_id = prefabs_collection.insert(json_prefab) + except ConnectionFailure: + print("ERROR: Could not connect to the mongoDB database.") + except DuplicateKeyError: + print("ERROR: A prefab with the same unique ID already exists in the database. \nPlease remove the '_id' before trying again.\nYour prefab has not been imported.") + except: + print("ERROR: A general error has occurred. Your prefab has not been imported.") + if prefab_id != None: + if name != None: + print(f'Prefab "{name}" has been imported successfully.') + else: + print(f'Prefab "{prefab_file}" has been imported successfully.') + except FileNotFoundError: + print(f"ERROR: {prefab_file} could not be found in the specified path. No prefabs have been imported.") + elif(re.match(r"\w+(\\\ \w*)*\.yml", prefab_file)): + print("expecting a yaml file here") + #yaml + else: + print("The filetype provided is an unsupported filetype.") + #unsupported filetype + +def clone(prefab_name, new_name): + bson = prefabs_collection.find_one({'name': prefab_name}) + json_string = dumps(bson) #convert BSON representation to JSON + chosen_prefab = json.loads(json_string) #load as a JSON object + + chosen_prefab.pop("_id") # clean out our _id field from the export: mongo will generate a new one if this is imported back in + + if new_name != None: + chosen_prefab["name"] = new_name + try: + prefab_id = prefabs_collection.insert_one(chosen_prefab) + except ConnectionFailure: + print("ERROR: Could not connect to the mongoDB database.") + except: + print("ERROR: A general error has occurred. Your selected prefab has not been cloned.") + if prefab_id != None: + if new_name != None: + print(f'Prefab "{prefab_name}" has been cloned successfully as {new_name}.') + else: + print(f'Prefab "{prefab_name}" has been cloned successfully.') + +def export(prefab_name, type): + bson = prefabs_collection.find_one({'name': prefab_name}) + json_string = dumps(bson) #convert BSON representation to JSON + chosen_prefab = json.loads(json_string) #load as a JSON object + + chosen_prefab.pop("_id") # clean out our _id field from the export: mongo will generate a new one if this is imported back in + + with open(f'{prefab_name}.json', 'w', encoding='utf8') as f: + json.dump(chosen_prefab, f, ensure_ascii=False, indent=4) + print(f'Prefab {prefab_name} written to {os.getcwd()}/{prefab_name}.json.') + #pprint.pprint(json_string) + #pprint.pprint(json.loads(str(json_string))) + +def list(): + #TODO: why does it output in single quotations? + cursor = prefabs_collection.find() + prefabs = [] + for record in cursor: + #pprint.pprint(record) + #print(record) + json_string = dumps(record, json_options=RELAXED_JSON_OPTIONS) ##pymongo retrieves BSON objects, which need to be converted to json for pythons json module + prefabs.append(json.loads(json_string)) + + #print(f'There are {str(len(prefabs))} prefabs in the database. They are:') + print("Name Author") + for prefab in prefabs: + if(prefab['visibility'] == "private"): + continue + print(f"{prefab['name']} {prefab['author']}") + #pprint.pprint(prefab) + + +def remove(prefab_name): + prefabs_collection.delete_one({'name': prefab_name}) + + -- cgit v1.2.3