fix relative directory paths and add common/libexec

This commit is contained in:
Michael Becker 2024-04-17 22:47:49 -04:00
parent 7ef120d30c
commit 6c65d4e278
33 changed files with 1894 additions and 10 deletions

View File

@ -0,0 +1,57 @@
from .Normalization import Normalization
from .core.Guid import Guid
class InstanceCache:
def __init__(self):
self.next_inst_id = dict()
self.next_inst_id[1] = 1
self.inst_indices = dict()
self.inst_guids = dict()
self.dbids_gid = dict()
def add_instance(self, inst_key, inst_gid):
self.inst_guids[inst_key] = inst_gid
self.inst_indices[inst_gid] = inst_key
if not inst_key[0] in self.next_inst_id:
self.next_inst_id[inst_key[0]] = 1
if inst_key[1] >= self.next_inst_id[inst_key[0]]:
self.next_inst_id[inst_key[0]] = inst_key[1] + 1
def get_global_identifier(self, inst_key):
return self.inst_guids[inst_key]
def get_instance_key(self, inst_gid):
return self.inst_indices[inst_gid]
def get_next_instance_id(self, class_index):
if not class_index in self.next_inst_id:
# this is the first instance of this class
self.next_inst_id[class_index] = 1
val = self.next_inst_id[class_index]
self.next_inst_id[class_index] += 1
return val
def has_instance_by_global_identifier(self, gid):
return gid in self.inst_indices
def count(self) -> int:
"""
Returns the number of instances stored in this OMS.
"""
return len(self.inst_indices)
def get_instance_keys(self):
return self.inst_indices
def set_database_id_by_global_identifier(self, gid : Guid, dbid):
self.dbids_gid[Normalization.normalize_uuid(gid.get_value())] = dbid
# self.dbids_idx[self.inst_indices[gid]] = dbid
def get_database_id_by_global_identifier(self, gid : Guid):
return self.dbids_gid[Normalization.normalize_uuid(gid.get_value())]

View File

@ -0,0 +1,443 @@
import MySQLdb
from .libraryparser import XMLLibraryParser, JSONLibraryParser, YAMLLibraryParser
from .LibraryOperation import LibraryOperation
from .operations.AssignAttributeOperation import AssignAttributeOperation
from .operations.AssignRelationshipOperation import AssignRelationshipOperation
from .operations.PrepareInstanceOperation import PrepareInstanceOperation
from .operations.StoredProcedureOperation import StoredProcedureOperation
from .Normalization import Normalization
from .core.Guid import Guid
from .core.KnownClassGuids import IDC_EntityDefinition, IDC_SourceDefinition
from .core.KnownAttributeGuids import *
from .core.KnownRelationshipGuids import *
from .InstanceCache import InstanceCache
from .SQLExpression import SQLExpression
from redis import Redis
class MochaLibraryManager:
def __init__(self):
self.entityReferences = dict()
self.entityReferenceFileNames = dict()
self.db = None
self._instances = []
self._attOps = []
self._relOps = []
self.redis = None
def connect(self, hostname, database, username, password):
self.db = MySQLdb.connect(host=hostname, user=username, passwd=password, db=database)
self.redis = Redis(host=hostname, port=6379, decode_responses=True)
def process_instance_ops(self):
# this version is much faster as it prepares everything in advanced on the CPU before
# pushing it out to the database
instances = InstanceCache()
for key in self._instances:
(class_gid, inst_gid, class_index, inst_index) = key
# first import all the known classes
if class_gid is not None and class_index is not None:
# print ("known class import")
# print ("class_gid = " + class_gid)
# print ("inst_gid = " + inst_gid + " (" + str(class_index) + "$" + str(inst_index) + ")")
if not instances.has_instance_by_global_identifier(class_gid):
instances.add_instance((1, class_index), class_gid)
for key in self._instances:
(class_gid, inst_gid, class_index, inst_index) = key
# now get all the classes without specified IIDs
if class_gid is not None and class_index is None:
# print ("unknown class import")
if not instances.has_instance_by_global_identifier(class_gid):
class_index = instances.get_next_instance_id(class_index)
else:
class_index = instances.get_instance_key(class_gid)[1]
if inst_index is None:
inst_index = instances.get_next_instance_id(class_index)
instances.add_instance((1, inst_index), inst_gid)
# print ("class_gid = " + class_gid)
# print ("inst_gid = " + inst_gid + " (" + str(1) + "$" + str(inst_index) + ")")
for key in self._instances:
(class_gid, inst_gid, class_index, inst_index) = key
if class_gid is not None and class_index is not None and inst_gid is not None and inst_index is not None:
# we know all there is to know about this one
pass
elif class_gid is not None and inst_gid is not None:
if class_index is None:
# we need to know the class index
if instances.has_instance_by_global_identifier(class_gid):
class_index = instances.get_instance_key(class_gid)[1]
else:
class_index = instances.get_next_instance_id(1)
if inst_index is None:
# we need to know the instance index as well
if instances.has_instance_by_global_identifier(inst_gid):
inst_index = instances.get_instance_key(inst_gid)[1]
else:
inst_index = instances.get_next_instance_id(class_index)
else:
print("error: not implemened class_gid is None or inst_gid is None")
instances.add_instance((class_index, inst_index), inst_gid)
print (str(instances.count()) + " instances preloaded")
c = 0
query = "INSERT INTO mocha_instances (tenant_id, class_id, inst_id, global_identifier) VALUES "
for inst_gid in instances.get_instance_keys():
(class_index, inst_index) = instances.get_instance_key(inst_gid)
print("preparing inst " + str(class_index) + "$" + str(inst_index) + " with guid " + inst_gid)
inst_key_str = str(class_index) + "$" + str(inst_index)
self.redis.set(inst_key_str + ".gid", Normalization.normalize_uuid(inst_gid))
self.redis.set(inst_key_str + ".attributes.count", "0")
self.redis.set(inst_key_str + ".relationships.count", "0")
self.redis.set(Normalization.normalize_uuid(inst_gid) + ".iid", inst_key_str)
self.redis.set(Normalization.normalize_uuid(inst_gid) + ".attributes.count", "0")
self.redis.set(Normalization.normalize_uuid(inst_gid) + ".relationships.count", "0")
query += "(1, " + str(class_index) + ", " + str(inst_index) + ", '" + Normalization.normalize_uuid(inst_gid) + "')"
if c < instances.count() - 1:
query += ", "
c += 1
print ("process_instance_ops: query was: ")
print (query)
self.db.query(query)
self.instances = instances
return True
def process_attribute_ops(self, ops):
query = "INSERT INTO mocha_attributes (tenant_id, src_inst_id, att_inst_id, usr_inst_id, att_effective_date, att_value) VALUES "
for op in ops:
instanceId = op.instanceId
attributeInstanceId = op.attributeInstanceId
value = op.value
if attributeInstanceId.get_value() == "":
print("skipping invalid blank attribute")
continue
print (instanceId.get_value() + " : " + attributeInstanceId.get_value() + " = '" + str(value) + "'")
# query += "(1, " \
# + "mocha_get_instance_by_global_identifier('" + Normalization.normalize_uuid(instanceId.get_value()) + "'), " \
# + "mocha_get_instance_by_global_identifier('" + Normalization.normalize_uuid(attributeInstanceId.get_value()) + "'), " \
# + "NULL, NOW(), " + SQLExpression.normalize_parm(value) + ")"
query += "(1, " \
+ str(self.instances.get_database_id_by_global_identifier(instanceId)) + ", " \
+ str(self.instances.get_database_id_by_global_identifier(attributeInstanceId)) + ", " \
+ "NULL, NOW(), " + SQLExpression.normalize_parm(value) + ")"
if ops.index(op) < len(ops) - 1:
query += ", "
# op.execute(self.db)
print ("process_attribute_ops: query was: ")
print (query)
self.db.query(query)
def process_relationship_ops(self, ops):
query = "INSERT INTO mocha_relationships (tenant_id, source_inst_id, relationship_inst_id, destination_inst_id, user_inst_id, effective_date) VALUES "
for op in ops:
instanceId = op.instanceId
relationshipInstanceId = op.relationshipInstanceId
targetInstanceId = op.targetInstanceId
print (instanceId.get_value() + " : " + relationshipInstanceId.get_value() + " = " + targetInstanceId.get_value())
query += "(1, " \
+ str(self.instances.get_database_id_by_global_identifier(instanceId)) + ", " \
+ str(self.instances.get_database_id_by_global_identifier(relationshipInstanceId)) + ", " \
+ str(self.instances.get_database_id_by_global_identifier(targetInstanceId)) + ", " \
+ "NULL, NOW() )"
if ops.index(op) < len(ops) - 1:
query += ", "
# op.execute(self.db)
print ("process_relationship_ops: query was: ")
print (query)
self.db.query(query)
def before_commit(self):
"""
Called before the unstructured information is sorted and written to the database.
---
This is your last chance to add instances, set attributes, and assign
relationships before the compilation is finalized. After this stage, calls made
to modify the compilation are undefined and will almost certainly not do what you
want.
"""
self.write_debug_information()
def write_debug_information(self):
"""
Writes debugging information, such as entity definitions ('&IDC_...;') and source
code definitions (filename, line number, column number, etc.)
"""
print ("preparing debug information (use --no-debug or undefine DEBUG or etc. [NOT IMPLEMENTED] to turn off)")
for key in self.entityReferences:
val = self.entityReferences[key]
gidEntityDefinition = Guid.create()
self.add_instance(IDC_EntityDefinition, gidEntityDefinition, None, None)
self.set_attribute_value(gidEntityDefinition, IDA_Name, key)
self.set_attribute_value(gidEntityDefinition, IDA_Value, val)
gidSourceDefinition = Guid.create()
self.add_instance(IDC_SourceDefinition, gidSourceDefinition, None, None)
self.set_attribute_value(gidSourceDefinition, IDA_DebugDefinitionFileName, self.entityReferenceFileNames[key])
self.assign_relationship(gidEntityDefinition, IDR_Instance__has__Source_Definition, gidSourceDefinition)
# Source Definition.has X
# self.add_instance(KnownClassGuids.CLASS, Guid("{dc0a5dd2-22e0-471f-87cf-a5ef1b764efa}"), 1, index)
# self.assign_relationship(instGid, Guid("{dc0a5dd2-22e0-471f-87cf-a5ef1b764efa}"), targetInstanceId)
def commit(self):
self.before_commit()
# first record all the instances
if not self.process_instance_ops():
return False
print("reading database ids...")
query = "SELECT id, global_identifier FROM mocha_instances"
cur = self.db.cursor()
cur.execute(query)
rows = cur.fetchall()
for (dbid, gid) in rows:
self.instances.set_database_id_by_global_identifier(Guid(gid), dbid)
print("assigning attributes...")
self.process_attribute_ops(self._attOps)
print("assigning relationships...")
self.process_relationship_ops(self._relOps)
hasSiblingRelationships = dict()
for op in self._relOps:
relationshipKey = self.instances
if op.relationshipInstanceId.get_value() == "{656110FF-4502-48B8-A7F3-D07F017AEA3F}":
# Relationship.has sibling Relationship
hasSiblingRelationships[op.instanceId.get_value()] = op.targetInstanceId
siblingOps = []
for op in self._relOps:
if op.relationshipInstanceId.get_value() in hasSiblingRelationships:
siblingOp = AssignRelationshipOperation(op.targetInstanceId, hasSiblingRelationships[op.relationshipInstanceId.get_value()], op.instanceId)
siblingOps.append(siblingOp)
# print ("assigning sibling relationship " + siblingOp.instanceId.get_value() + " . " + siblingOp.relationshipInstanceId.get_value() + " = " + siblingOp.instanceId.get_value())
# siblingOp.execute(self.db)
print("assigning sibling relationships...")
self.process_relationship_ops(siblingOps)
print("setting creation user...")
cur = self.db.cursor()
# cur.execute("UPDATE mocha_instances SET user_inst_id = mocha_get_instance_by_global_identifier(mocha_normalize_uuid('{B066A54B-B160-4510-A805-436D3F90C2E6}'))")
cur.execute("UPDATE mocha_attributes SET usr_inst_id = " + str(self.instances.get_database_id_by_global_identifier(Guid("{B066A54B-B160-4510-A805-436D3F90C2E6}"))))
cur.execute("UPDATE mocha_relationships SET user_inst_id = " + str(self.instances.get_database_id_by_global_identifier(Guid("{B066A54B-B160-4510-A805-436D3F90C2E6}"))))
# rows = cur.fetchall()
# print(rows)
# print ("ok , applying `Class.has Instance`...")
# for row in rows:
# print(row)
# id = row[0]
# tenant_id = row[1]
# class_id = row[2]
# inst_id = row[3]
# global_identifier = row[4]
# if class_id is not None and id is not None:
# # Class.has Instance
# query2 = ("CALL mocha_assign_relationship (" +
# "mocha_get_instance_by_key(1, " + str(class_id) + "), " +
# "mocha_get_instance_by_global_identifier(mocha_normalize_uuid('7EB41D3C-2AE9-4884-83A4-E59441BCAEFB'))" + ", " +
# str(id) + ", NULL, NULL)")
# cur.execute(query2)
# # Instance.for Class
# query3 = ("CALL mocha_assign_relationship (" +
# str(id) + ", " +
# "mocha_get_instance_by_global_identifier(mocha_normalize_uuid('494D5A6D-04BE-477B-8763-E3F57D0DD8C8'))" + ", " +
# "mocha_get_instance_by_key(1, " + str(class_id) + "), NULL, NULL)")
# cur.execute(query3)
self.db.commit()
def close(self):
self.db.close()
def print_error(self, cur):
rows = cur.fetchall()
for row in rows:
if 'error_description' in row:
print (row['error_description'])
def select_tenant(self, tenantName):
cur = self.db.cursor()
cur.execute("CALL mocha_select_tenant(mocha_get_tenant_by_name('" + tenantName + "'))")
self.print_error(cur)
def release_tenant(self):
cur = self.db.cursor()
cur.execute("CALL mocha_release_tenant()")
self.print_error(cur)
def assign_relationship(self, instanceId : Guid, relationshipInstanceId : Guid, targetInstanceId : Guid):
print("-- assigning relationship " + relationshipInstanceId.get_value() + " = '" + targetInstanceId.get_value() + "'")
self._relOps.append(AssignRelationshipOperation(instanceId, relationshipInstanceId, targetInstanceId))
# self._relOps.append(AssignRelationshipOperation(instanceId, relationshipInstanceId, targetInstanceId))
# query = "CALL mocha_assign_relationship(mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + instanceId.get_value() + "')), mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + relationshipInstanceId.get_value() + "')), mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + targetInstanceId.get_value() + "')), NULL, NULL);"
# print(query)
# cur.execute(query)
# self.print_error(cur)
def set_attribute_value(self, instanceId : Guid, attributeInstanceId : Guid, value):
print("-- assigning attribute " + attributeInstanceId.get_value() + " = '" + str(value) + "'")
self._attOps.append(AssignAttributeOperation(instanceId, attributeInstanceId, value))
def install_from_path(self, path):
from glob import glob
xl = XMLLibraryParser(self)
jl = JSONLibraryParser(self)
yl = YAMLLibraryParser(self)
#xml_files = glob(path + "/**/*.xml", recursive=True)
#for xml_file in xml_files:
#s xl.load_file(xml_file)
#json_files = glob(path + "/**/*.json", recursive=True)
#for json_file in json_files:
# jl.load_file(json_file)
yaml_files = sorted(glob(path + "/**/*.yaml", recursive=True))
if len(yaml_files) == 0:
print ("no files found ; does the path exist?")
return 3
# first, load the entity defs
for yaml_file in yaml_files:
yl.load_entity_definitions_from_file(yaml_file)
try:
# then, load instance definitions (also loads sugar elements into memory for later use)
for yaml_file in yaml_files:
yl.load_instances_from_file(yaml_file)
# finally, apply syntactic sugar
yl.apply_sugar()
return True
except NameError as ex:
print (ex)
rgx = "&(.*);"
# go through and get all entity references across all files
import re
import fileinput
stuff = []
for yaml_file in yaml_files:
f = open(yaml_file, "r")
text = f.read()
matches = re.findall(rgx, text)
for match in matches:
stuff.append(match)
f.close()
missingEntities = []
for stuf in stuff:
if not stuf in self.entityReferences:
if not stuf in missingEntities:
missingEntities.append(stuf)
if len(missingEntities) > 0:
print("\nNOTE: there were undefined referenced entities:\n")
for missingEntity in missingEntities:
print("\t" + missingEntity)
print("\n")
return False
def exists_entity_reference(self, name):
return name in self.entityReferences
def register_entity_reference(self, name, value, filename = None):
self.entityReferences[name] = value
self.entityReferenceFileNames[name] = filename
def define_entity_reference(self, name):
return self.entityReferences[name]
def expand_entity_references(self, value):
insideName = False
name = ""
retval = ""
for i in range(0, len(value)):
if value[i] == "&":
insideName = True
elif value[i] == ';':
insideName = False
if name in self.entityReferences:
retval += self.define_entity_reference(name)
else:
raise NameError("unknown entity ref '" + name + "'")
name = ""
elif insideName:
name += value[i]
else:
retval += value[i]
return retval
def add_instance(self, classGid : Guid, instGid : Guid, classIndex : int, index : int):
print("adding instance for class '" + classGid.get_value() + "' with globalid '" + instGid.get_value() + "' [" + str(index) + "]")
self._instances.append((classGid.get_value(), instGid.get_value(), classIndex, index))
# assign relationship `Instance.for Class`
self.assign_relationship(instGid, Guid('494D5A6D04BE477B8763E3F57D0DD8C8'), classGid)
# assign relationship `Class.has Instance`
self.assign_relationship(classGid, Guid('7EB41D3C2AE9488483A4E59441BCAEFB'), instGid)

View File

@ -0,0 +1,21 @@
import MySQLdb
from MySQLdb.connections import Connection
class LibraryOperation:
def build_query(self):
return ''
def print_error(self, cur):
rows = cur.fetchall()
for row in rows:
if 'error_description' in row:
print (row['error_description'])
def execute(self, db : Connection):
cur = db.cursor()
query = self.build_query()
print(query)
cur.execute(query)
self.print_error(cur)

View File

@ -0,0 +1,5 @@
class Normalization:
@staticmethod
def normalize_uuid(val : str):
val = val.replace("{", "").replace("}", "").replace("-", "").strip().lower()
return val

View File

@ -0,0 +1,47 @@
from .core.Guid import Guid
from .Normalization import Normalization
class SQLExpression:
@staticmethod
def sqlescape(parm : str):
return parm.replace("'", "\\'")
@staticmethod
def normalize_parm(parm : str):
query = ""
if parm == None:
query += "NULL"
elif isinstance(parm, Guid):
gid = None
if parm is not None:
gid = "'" + Normalization.normalize_uuid(parm.get_value()) + "'"
else:
gid = "NULL"
query += gid
elif isinstance(parm, str):
query += "'" + SQLExpression.sqlescape(str(parm)) + "'"
else:
query += str(parm)
return query
@staticmethod
def to_string(parm):
return SQLExpression.normalize_parm(parm)
@staticmethod
def array_to_string(parms):
i = 0
query = ''
for parm in parms:
query += SQLExpression.to_string(parm)
if i < len(parms) - 1:
query += ", "
i += 1
return query

View File

@ -0,0 +1,20 @@
from .SQLExpression import SQLExpression
class SQLFunctionCall (SQLExpression):
def __init__(self, funcname, parms):
self.name = funcname
self.parms = parms
def get_name(self):
return self.name
def get_parameters(self):
return self.parms
def get_parameter_list(self):
return SQLExpression.array_to_string(self.parms)
def __str__(self):
return self.get_name() + "(" + self.get_parameter_list() + ")"

View File

@ -0,0 +1,12 @@
from .SQLExpression import SQLExpression
class SQLParameter (SQLExpression):
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
def __str__(self):
return "@" + self.get_name()

View File

@ -0,0 +1,15 @@
class Guid:
def __init__(self, val : str):
self.value = val
def get_value(self) -> str:
return self.value
@staticmethod
def create():
from uuid import uuid4
u = uuid4()
g = Guid(str(u))
return g

View File

@ -0,0 +1,18 @@
from .Guid import Guid
"""
Represents the Text Attribute `Name`
"""
IDA_Name = Guid("{9153A637-992E-4712-ADF2-B03F0D9EDEA6}")
"""
Represents the Text Attribute `Value`
"""
IDA_Value = Guid("{041DD7FD-2D9C-412B-8B9D-D7125C166FE0}")
"""
Represents the Text Attribute `Debug Definition File Name`
"""
IDA_DebugDefinitionFileName = Guid("{03bf47c7-dc97-43c8-a8c9-c6147bee4e1f}")
IDA_DebugDefinitionLineNumber = Guid("{822be9b7-531d-4aa1-818a-6e4de1609057}")
IDA_DebugDefinitionColumnNumber = Guid("{0f75c750-e738-4410-9b4e-deb422efc7aa}")

View File

@ -0,0 +1,5 @@
from .Guid import Guid
IDC_SourceDefinition = Guid("{5d0b2f03-4886-4ba6-ac3c-8f9612963fa6}")
IDC_EntityDefinition = Guid("{15ffa529-6aab-4f1f-8720-f2534951b045}")

View File

@ -0,0 +1,3 @@
from .Guid import Guid
IDR_Instance__has__Source_Definition = Guid("{57cbc351-0428-47e6-a6db-445e4503abab}")

View File

@ -0,0 +1,30 @@
from .LibraryParser import LibraryParser
class JSONLibraryParser (LibraryParser):
def cstyle_strip_comments(self, val):
val2 = ""
# possible values for comment: 0 = none, 1 = multiline, 2 = singleline
comment = 0
xr = iter(range(0, len(val) - 1))
for i in xr:
if val[i] == '\n' and comment == 2:
comment = 0
check = val[i:i+2]
if check == "/*" and comment == 0:
comment = 1
next(xr)
elif check == "*/" and comment == 1:
comment = 0
next(xr)
elif check == "//":
comment = 2
next(xr)
elif comment == 0:
val2 += val[i]
val2 += val[-1:]
return val2

View File

@ -0,0 +1,4 @@
class LibraryParser():
def __init__(self, manager):
self.__manager = manager

View File

@ -0,0 +1,5 @@
class MochaSyntaxError(RuntimeError):
def __init__(self, *args):
RuntimeError.__init__(self, args)
pass

View File

@ -0,0 +1,46 @@
from .LibraryParser import LibraryParser
from xml.dom import minidom, Node
from xml.dom.minidom import Entity
class XMLLibraryParser(LibraryParser):
def load_instance(self, xmlnode):
print("instance : [" + xmlnode.getAttribute("id") + "]")
def load_library(self, xmlnode):
"""
Loads a library from the specified XML node.
"""
raise NotImplementedError()
if xmlnode.tagName != "library":
return
id = xmlnode.getAttribute("id")
for child in xmlnode.childNodes:
if child.tagName == "instances":
for child2 in child.childNodes:
self.load_library_instance_from_xml(child)
def load_file(self, filename):
print("loading xml from " + filename + "... ")
dom = minidom.getDOMImplementation()
dt = dom.createDocumentType("mocha", "-//MBS//DTD Mocha 1.0 Dev//EN", "https://doctype.schemas.alcetech.net/Mocha/1.0/mocha-1.0.dtd")
dt.entities.setNamedItem(Entity("IDC_ReturnInstanceSetMethodBinding", "{AADC20F9-7559-429B-AEF0-97E059295C76}", None, None))
dom = minidom.parse(filename)
if (dom.documentElement.tagName != "mocha"):
print(filename + ": top-level tag is not 'mocha'")
return
for child in dom.documentElement.childNodes:
if child.nodeType == Node.ELEMENT_NODE:
if child.tagName == "libraries":
for child2 in child.childNodes:
self.load_library(child)
print ("\n")

View File

@ -0,0 +1,345 @@
from .LibraryParser import LibraryParser
from ..core.Guid import Guid
from .MochaSyntaxError import MochaSyntaxError
class YAMLLibraryParser (LibraryParser):
def __init__(self, manager):
LibraryParser.__init__(self, manager)
self.yamlIds = dict()
self.templates = dict()
# these two are special reserved tagNames
# self.yamlIds["entityDefinitions"] = None
# self.yamlIds["instance"] = { }
self.manager = manager
self._instances_awaiting_sugar = []
def apply_sugar(self):
print("applying syntactic sugar to remaining instances...")
# _instances_also_awaiting_sugar = []
for inst in self._instances_awaiting_sugar:
print("applying sugar from '" + inst["from_file_name"] + "'")
self.load_instance(inst)
print("\n")
# do recursively until we're all out of instances awaiting sugar
# if len(self._instances_awaiting_sugar) > 0:
# self.apply_sugar()
def load_library(self, elem):
print("loading library from elem")
def load_tenant(self, elem):
print("loading tenant from elem")
def find_custom_tag_name(self, elem) -> (str, Guid):
# return tuple (tagname, value)
if "instance" in elem:
return ("instance", Guid(self.manager.expand_entity_references(elem["instance"])))
for key in self.yamlIds:
if key in elem:
k = str(key)
v = Guid(self.manager.expand_entity_references(elem[key]))
return (k, v)
return (None, None)
def load_entity_definitions_from_file(self, filename):
print("loading entity defs from " + filename)
import yaml
with open(filename, 'r') as file:
content = yaml.safe_load_all(file)
for doc in content:
for elem in doc:
if "entityDefinitions" in elem:
entities = elem["entityDefinitions"]
if not entities is None:
for entity in entities:
for key in entity:
if self.manager.exists_entity_reference(key):
print("duplicate entity definition: '" + key + "'")
exit(1)
self.manager.register_entity_reference(key, entity[key], filename)
def load_instance_with_template(self, elem, template):
(parentCreatorKey, parentInstanceId) = self.find_custom_tag_name(template)
(creatorKey, instanceId) = self.find_custom_tag_name(elem)
self.apply_template(elem, template, instanceId)
def assign_relationship_value(self, instanceId, rel, rel_iid, relationshipValue):
if (isinstance(relationshipValue, str)):
# single instance, this should be a GUID or entityref
# we should only need to refer to existing instance in this case
relationshipValueInst = Guid(self.manager.expand_entity_references(relationshipValue))
if "instance" in rel:
self.manager.assign_relationship(instanceId, Guid(self.manager.expand_entity_references(rel["instance"])), relationshipValueInst)
else:
print("no relationship instance specified for relationship sugar")
else:
# dynamically created instance
#FIXME: this 'instance' isn't always the tag name, this can be subject to customTagName as well!and should be processed accordingly
(relinst_key, relinst_iid) = self.find_custom_tag_name(relationshipValue)
if relinst_key is not None:
# for example, 'relinst_key' is 'elementContent' and 'relinst_iid' is '{8ECA14A4...}'
if rel_iid is not None:
print("found customTagName '" + str(relinst_key) + "' with value '" + str(relinst_iid.get_value()) + "'")
# relval = Guid(self.manager.expand_entity_references(elem[customTagName]))
# we need to create the new instance and assign relationship
self.manager.assign_relationship(instanceId, rel_iid, relinst_iid)
else:
if "globalIdentifier" in relationshipValue:
globalIdentifier = Guid(relationshipValue["globalIdentifier"])
else:
globalIdentifier = Guid.create()
print("creating new instance for relationship '%s' with globalid '%s'" % (rel_iid, globalIdentifier.get_value()))
createsInstanceOf = None
if "type" in relationshipValue:
print("found relationship override type '%s'" % (relationshipValue['type']))
createsInstanceOf = Guid(self.manager.expand_entity_references(relationshipValue["type"]))
elif "customTagNameCreatesInstanceOf" in rel:
createsInstanceOf = Guid(self.manager.expand_entity_references(rel["customTagNameCreatesInstanceOf"]))
if not createsInstanceOf is None:
# create the new instance
self.manager.add_instance(createsInstanceOf, globalIdentifier, None, None)
# assign relationships
self.manager.assign_relationship(instanceId, rel_iid, globalIdentifier)
# self.manager.assign_relationship(globalIdentifier, relationshipInstanceId, instanceId)
# FIXME: apply relationships from the parent class template
#? NOTE: You MUST specify 'registerForTemplate: yes' on the template definition for
#? sibling relationships to be properly applied!
if createsInstanceOf.get_value() in self.templates:
print("applying template for createsInstanceOf '%s'" % (createsInstanceOf.get_value()))
createsInstanceOfTemplate = self.templates[createsInstanceOf.get_value()]
self.apply_template(relationshipValue, createsInstanceOfTemplate, globalIdentifier)
else:
print("no template registered for createsInstanceOf '%s'" % (createsInstanceOf.get_value()))
else:
print ("neither createsInstanceOf nor override 'type' present for relationship value")
def apply_template(self, elem, template, instanceId):
if "value" in elem:
print("VALUE found in ELEM:")
print(elem["value"])
if "attributes" in template:
attrs = template["attributes"]
if isinstance(attrs, list):
for attr in attrs:
if "customTagName" in attr:
customTagName = attr["customTagName"]
if customTagName in elem:
attrinst = Guid(self.manager.expand_entity_references(attr["instance"]))
attrval = elem[customTagName]
self.manager.set_attribute_value(instanceId, attrinst, attrval)
if "relationships" in template:
rels = template["relationships"]
for rel in rels:
if "instance" in rel:
rel_iid = rel["instance"] # the globalId of the relationship instance
else:
print("no relationship instance specified for relationship sugar")
continue
if "customTagName" in rel:
customTagName = rel["customTagName"]
if customTagName in elem:
relationshipValue = elem[customTagName]
if relationshipValue is None:
continue
if isinstance(relationshipValue, list):
# multiple instances
for v in relationshipValue:
self.assign_relationship_value(instanceId, rel, Guid(self.manager.expand_entity_references(rel_iid)), v)
else:
self.assign_relationship_value(instanceId, rel, Guid(self.manager.expand_entity_references(rel_iid)), relationshipValue)
def get_instance_sugar_for_elem(self, elem):
if "instance" in elem:
return (elem["instance"], "instance", None)
else:
for key in self.yamlIds:
# no 'instance', see if we
if key in elem:
template = self.yamlIds[key]
templateKey = key
return (elem[templateKey], templateKey, template)
return (None, None, None) # should never get here
def load_instance(self, elem, elemParent = None):
# 'class' and 'relationship' are both at the 'same level'
# so we can't define 'relationship' without first defining 'class'
# we could try to keep looping as long as we're still getting "unknown tag name"
# (instanceID is None), but we could get stuck that way...
# for now, let's just forward define important classes (e.g. IDC_Relationship)
# all of these problems could be avoided by simply
# LOADING EVERYTHING INTO MEMORY (like the .NET version does)
# and only committing to the DB at the very end
# this will resolve problems where we can't find instances, or use syntactic sugar
(globalIdentifier, templateKey, template) = self.get_instance_sugar_for_elem(elem)
print ("globalIdentifier = " + str(globalIdentifier) + ", templateKey = " + str(templateKey))
if template is None:
# no sugar
pass
customTagName = None
if "customTagName" in elem:
customTagName = elem["customTagName"]
self.yamlIds[customTagName] = elem
print("registering customTagName '" + customTagName + "'")
if "registerForTemplate" in elem:
if elem["registerForTemplate"] == True:
self.templates[self.manager.expand_entity_references(globalIdentifier)] = elem
print("registering elem for template")
classId = None
classIndex = None
if template is None and elemParent is not None:
template = elemParent
if template is not None:
if "instance" in template:
classId = Guid(self.manager.expand_entity_references(template["instance"]))
else:
for key in self.yamlIds:
if key in template:
classId = Guid(self.manager.expand_entity_references(template[key]))
break
if "index" in template:
classIndex = template["index"]
instanceId = None
creatorKey = None
if "instance" in elem:
if "templateOnly" in elem and elem["templateOnly"] == True:
# instanceId = None
instanceId = Guid(self.manager.expand_entity_references(elem["instance"]))
else:
instanceId = Guid(self.manager.expand_entity_references(elem["instance"]))
creatorKey = 'instance'
else:
for key in self.yamlIds:
if key in elem:
instanceId = Guid(self.manager.expand_entity_references(elem[key]))
creatorKey = key
break
index = None
if "index" in elem:
index = elem["index"]
# else:
# print("index not found for element")
# print(elem)
if classId is None and instanceId is not None:
#!!! HACK HACK HACK !!!
classId = instanceId
if classIndex is None and index is None:
classIndex = 1
index = 1
print("WARNING: class hack used for instanceId " + instanceId.get_value() + " ( index " + str(classIndex) + "$" + str(index) + ")")
if instanceId is not None:
self.manager.add_instance(classId, instanceId, classIndex, index)
if creatorKey == 'class': #FIXME: remove this special-case behavior
print("creating class " + instanceId.get_value())
# # assign relationship `Instance.for Class`
# self.manager.assign_relationship(instanceId, Guid('494D5A6D04BE477B8763E3F57D0DD8C8'), Guid('B9C9B9B7AD8A4CBDAA6BE05784630B6B'))
# # assign relationship `Class.has Instance`
# self.manager.assign_relationship(Guid('B9C9B9B7AD8A4CBDAA6BE05784630B6B'), Guid('7EB41D3C2AE9488483A4E59441BCAEFB'), instanceId)
if "instances" in elem:
classInsts = elem["instances"]
for inst in classInsts:
self.load_instance(inst, elem)
else:
print("creating instance " + instanceId.get_value() + " (of class " + classId.get_value() + ")")
# # assign relationship `Instance.for Class`
# self.manager.assign_relationship(instanceId, Guid('494D5A6D04BE477B8763E3F57D0DD8C8'), classId)
# # assign relationship `Class.has Instance`
# self.manager.assign_relationship(classId, Guid('7EB41D3C2AE9488483A4E59441BCAEFB'), instanceId)
# self.manager.create_instance_of(classId, instanceId, classIndex, index)
if templateKey is not None:
if template is not None:
print("using template (" + templateKey + ")")
#print(template)
self.load_instance_with_template(elem, template)
else:
#print("ignoring '" + templateKey + "'")
pass
def load_instances_from_file(self, filename):
print("loading instances from " + filename)
import yaml
with open(filename, 'r') as file:
content = yaml.safe_load_all(file)
for doc in content:
for elem in doc:
if "entityDefinitions" in elem:
continue
elif "library" in elem:
self.load_library(filename, elem)
elif "tenant" in elem:
self.load_tenant(filename, elem)
else:
raise MochaSyntaxError("neither 'library' nor 'tenant' top level element found")
def load_library(self, filename, elem):
if "instances" in elem:
instances = elem["instances"]
for elem1 in instances:
if "instance" in elem1:
# this is an instance definition (no sugar), so just load it
self.load_instance(elem1)
else:
# this is a syntactic sugar definition, so store it for later use
elem1["from_file_name"] = filename
self._instances_awaiting_sugar.append(elem1)
def load_tenant(self, filename, elem):
pass

View File

@ -0,0 +1,4 @@
from .LibraryParser import LibraryParser
from .JSONLibraryParser import JSONLibraryParser
from .XMLLibraryParser import XMLLibraryParser
from .YAMLLibraryParser import YAMLLibraryParser

View File

@ -0,0 +1,21 @@
from .StoredProcedureOperation import StoredProcedureOperation
from ..core.Guid import Guid
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
class AssignAttributeOperation(StoredProcedureOperation):
def __init__(self, instanceId : Guid, attributeInstanceId : Guid, value):
self.instanceId = instanceId
self.attributeInstanceId = attributeInstanceId
self.value = value
def get_sp_name(self):
return "mocha_set_attribute_value"
def get_sp_parameters(self):
return [ SQLFunctionCall('mocha_get_instance_by_global_identifier', [ self.instanceId ]), SQLFunctionCall('mocha_get_instance_by_global_identifier', [ self.attributeInstanceId ]), str(self.value), None, None ]
#query = "CALL mocha_set_attribute_value(mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + instanceId.get_value() + "')), mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + attributeInstanceId.get_value() + "')), '" + str(value) + "', NULL, NULL);"
#print(query)
#cur.execute(query)
#self.print_error(cur)

View File

@ -0,0 +1,21 @@
from .StoredProcedureOperation import StoredProcedureOperation
from ..core.Guid import Guid
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
class AssignRelationshipOperation(StoredProcedureOperation):
def __init__(self, instanceId : Guid, relationshipInstanceId : Guid, targetInstanceId : Guid):
self.instanceId = instanceId
self.relationshipInstanceId = relationshipInstanceId
self.targetInstanceId = targetInstanceId
def get_sp_name(self):
return "mocha_assign_relationship"
def get_sp_parameters(self):
return [ SQLFunctionCall('mocha_get_instance_by_global_identifier', [ self.instanceId ]), SQLFunctionCall('mocha_get_instance_by_global_identifier', [ self.relationshipInstanceId ]), SQLFunctionCall('mocha_get_instance_by_global_identifier', [ self.targetInstanceId ]), None, None ]
#query = "CALL mocha_set_attribute_value(mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + instanceId.get_value() + "')), mocha_get_instance_by_global_identifier(mocha_normalize_uuid('" + attributeInstanceId.get_value() + "')), '" + str(value) + "', NULL, NULL);"
#print(query)
#cur.execute(query)
#self.print_error(cur)

View File

@ -0,0 +1,17 @@
from .StoredProcedureOperation import StoredProcedureOperation
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
from ..core.Guid import Guid
class CreateClassOperation (StoredProcedureOperation):
def __init__(self, globalIdentifier : Guid, classIndex : int):
self.globalIdentifier = globalIdentifier
self.classIndex = classIndex
def get_sp_name(self):
return 'mocha_create_class'
def get_sp_parameters(self):
return [ self.classIndex, self.globalIdentifier, None, None, SQLParameter("dummy") ]

View File

@ -0,0 +1,17 @@
from .StoredProcedureOperation import StoredProcedureOperation
from ..core.Guid import Guid
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
class CreateInstanceOperation(StoredProcedureOperation):
def __init__(self, globalIdentifier : Guid, classIndex : int, instanceIndex : int):
self.globalIdentifier = globalIdentifier
self.classIndex = classIndex
self.instanceIndex = instanceIndex
def get_sp_name(self):
return 'mocha_create_instance'
def get_sp_parameters(self):
return [ self.globalIdentifier, self.classIndex, self.instanceIndex, None, None, SQLParameter('assigned_inst_id') ]

View File

@ -0,0 +1,36 @@
from .StoredProcedureOperation import StoredProcedureOperation
from ..core.Guid import Guid
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
class PrepareInstanceOperation(StoredProcedureOperation):
def __init__(self, classGlobalIdentifier : Guid, globalIdentifier : Guid, classIndex : int, instanceIndex : int):
self.classGlobalIdentifier = classGlobalIdentifier
self.globalIdentifier = globalIdentifier
self.classIndex = classIndex
self.instanceIndex = instanceIndex
def get_sp_name(self):
return "mocha_prepare_instance"
def get_sp_parameters(self):
parms = []
globalId = None
if self.globalIdentifier is not None:
globalId = self.globalIdentifier
classGlobalId = None
if self.classGlobalIdentifier is not None:
classGlobalId = self.classGlobalIdentifier
strCid = None
if self.classIndex is not None:
strCid = self.classIndex
strIid = None
if self.instanceIndex is not None:
strIid = self.instanceIndex
return [strCid, strIid, classGlobalId, globalId, None, None, SQLParameter("p_assigned_inst_id")]

View File

@ -0,0 +1,24 @@
import MySQLdb
from ..LibraryOperation import LibraryOperation
from MySQLdb.connections import Connection
from ..SQLExpression import SQLExpression
from ..SQLParameter import SQLParameter
from ..SQLFunctionCall import SQLFunctionCall
from ..core.Guid import Guid
class StoredProcedureOperation (LibraryOperation):
def get_sp_name(self):
return ''
def get_sp_parameters(self):
return []
def build_query(self):
query = "CALL " + self.get_sp_name() + "("
parms = self.get_sp_parameters()
query += SQLExpression.array_to_string(parms)
query += ")"
return query

View File

@ -0,0 +1,46 @@
import os, sys
from librarymanager.LibraryManager import MochaLibraryManager
if __name__ == "__main__":
mlm = MochaLibraryManager()
path = None
dbname = None
dbuser = None
dbpass = None
tenantName = 'super'
if len(sys.argv) == 2:
path = sys.argv[1]
print("installing mocha from path: " + path)
elif len(sys.argv) == 5:
path = sys.argv[4]
dbname = sys.argv[1]
dbuser = sys.argv[2]
dbpass = sys.argv[3]
print("installing mocha from path: " + path)
print("using dbname = " + dbname + ", dbuser = " + dbuser)
elif len(sys.argv) == 6:
tenantName = sys.argv[1]
path = sys.argv[5]
dbname = sys.argv[2]
dbuser = sys.argv[3]
dbpass = sys.argv[4]
print("installing mocha from path: " + path)
print("using dbname = " + dbname + ", dbuser = " + dbuser)
else:
print("usage: mocha-install-library TENANTNAME [DATABASENAME USERNAME PASSWORD] PATH_TO_LIBRARY")
exit(3)
mlm.connect('localhost', dbname, dbuser, dbpass)
mlm.select_tenant(tenantName)
result = mlm.install_from_path(path)
if result:
mlm.commit()
mlm.close()

View File

@ -0,0 +1,34 @@
import os
import sys
import zipfile
def zipdir(path, ziph):
# ziph is zipfile handle
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".xml") or file == "manifest.inf":
ziph.write(os.path.join(root, file),
os.path.relpath(os.path.join(root, file),
os.path.join(path, '..')))
if len(sys.argv) > 1:
if sys.argv[1] == "build":
if len(sys.argv) > 2:
# usage: mocha lib build (folder) (filename.zip)
if len(sys.argv) > 3:
with zipfile.ZipFile(sys.argv[3], 'w', zipfile.ZIP_DEFLATED) as zipf:
zipdir(sys.argv[2], zipf)
else:
print ("usage: mocha lib build FILENAME")
else:
print ("usage: mocha lib build")
else:
print ("usage: mocha lib build")

View File

@ -0,0 +1,21 @@
#!/bin/bash
if [ $# -gt 0 ]; then
if [ -f "/usr/lib/mocha/mocha-$1" ]; then
MOCHA_COMMAND=$1
shift
exec "/usr/lib/mocha/mocha-$MOCHA_COMMAND" ${1+"$@"}
else
echo "mocha: '$1' is not a mocha command. See 'mocha --help'."
fi
else
echo "usage: mocha $(echo /usr/lib/mocha/mocha-* | sed -e 's/\/usr\/lib\/mocha\/mocha\-//g' -e 's/ /|/g')"
fi

View File

@ -0,0 +1,19 @@
#!/bin/bash
if [ "$1" != "-y" ]; then
echo "ARE YOU SURE you wish to CLEAN this SUV?"
echo "This will DESTROY all data and rebuild from a clean master image."
echo ""
echo -n "Type YES to confirm: > "
read CONFIRMYES
if [ "$CONFIRMYES" != "YES" ]; then
echo ""
echo "OK, not doing anything"
exit 1
fi
fi
rm /etc/mocha/*
mocha up

View File

@ -0,0 +1,3 @@
#!/bin/sh
/usr/bin/python3 mocha-lib.py ${1+"$@"}

View File

@ -0,0 +1,363 @@
#!/bin/bash
MOCHA_DBNAME=$(cat /etc/mocha/dbname)
MOCHA_DBUSER=$(cat /etc/mocha/dbuser)
MOCHA_DBPASS=$(cat /etc/mocha/dbpass)
MOCHA_MYSQL="mysql -D $MOCHA_DBNAME -u $MOCHA_DBUSER --password=$MOCHA_DBPASS"
if [ ! -d ~/.config ]; then
mkdir ~/.config
fi
if [ ! -d ~/.config/mocha ]; then
mkdir ~/.config/mocha
fi
if [ -f ~/.config/mocha/tenant ]; then
CURRENT_TENANT=$(cat ~/.config/mocha/tenant)
#echo "current tenant: $CURRENT_TENANT"
#echo "use 'mocha oms tenant select' to change"
fi
if [ "$1" == "install" ]; then
if [ "$2" == "library" ]; then
echo "installing Mocha OMS from library '$3'..."
python3 /usr/lib/mocha/internal/mocha-install-library.py $CURRENT_TENANT $MOCHA_DBNAME $MOCHA_DBUSER $MOCHA_DBPASS $3
else
echo "installing Mocha OMS from SQL..."
cd /usr/lib/mocha/sql/php
php ./install_mysql.php $MOCHA_DBNAME $MOCHA_DBUSER $MOCHA_DBPASS
$MOCHA_MYSQL -e "CALL mocha_select_tenant(1);" -e "CALL mocha_build_tenant_from_template(mocha_get_current_tenant(), 1);" -e "CALL mocha_release_tenant();"
fi
elif [ "$1" == "tenant" ]; then
if [ "$2" == "list" ]; then
if [ "$3" == "names" ]; then
$MOCHA_MYSQL -N -s -e "SELECT tenant_name FROM mocha_tenants"
else
$MOCHA_MYSQL -e "SELECT * FROM mocha_tenants"
fi
elif [ "$2" == "create" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant create TENANTNAME"
exit
fi
$MOCHA_MYSQL -e "CALL mocha_create_tenant('$3', NULL)"
$MOCHA_MYSQL -e "CALL mocha_build_tenant_from_template(mocha_get_tenant_by_name('$3'), 1);"
OLDTENANT=$(mocha oms tenant)
mocha oms tenant select $3
mocha oms install library /usr/share/mocha/libraries/
mocha oms tenant select $OLDTENANT
elif [ "$2" == "delete" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant delete TENANTNAME"
fi
if [ "$3" == "super" ]; then
echo "cannot delete the super tenant!"
exit
fi
$MOCHA_MYSQL -e "DELETE FROM mocha_tenants WHERE tenant_name = '$3'"
elif [ "$2" == "select" ]; then
if [ $# -lt 3 ]; then
echo "usage: mocha oms tenant select TENANTNAME"
exit
fi
echo $3 > ~/.config/mocha/tenant
echo "current tenant: $3"
elif [ "$2" == "release" ]; then
rm ~/.config/mocha/tenant
echo "current tenant: (none)"
elif [ "$2" == "" ]; then
if [ -f ~/.config/mocha/tenant ]; then
echo $(cat ~/.config/mocha/tenant)
fi
fi
elif [ "$1" == "user" ]; then
if [ "$CURRENT_TENANT" == "" ]; then
echo "no tenant selected; please 'mocha oms tenant select' first"
exit
fi
if [ "$2" == "list" ]; then
$MOCHA_MYSQL -e "SELECT * FROM mocha_instances WHERE class_id = 39 AND tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT')";
elif [ "$2" == "add" ]; then
if [ "$3" != "" ]; then
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "CALL mocha_create_user('$3', NULL);" -e "CALL mocha_release_tenant();"
echo $3
else
echo "usage: mocha oms user add USERNAME"
fi
elif [ "$2" == "set-password" ]; then
if [ "$3" == "" ]; then
echo "usage: mocha oms user set-password USERNAME [PASSWORD]"
exit
fi
PASSWORD=$4
if [ "$PASSWORD" == "" ]; then
echo "Changing password for $3."
stty -echo
read -p "New password: " PASSWORD
stty echo
echo ""
stty -echo
read -p "Retype new password: " PASSWORD2
stty echo
echo ""
echo ""
if [ "$PASSWORD" != "$PASSWORD2" ]; then
echo "Sorry, passwords do not match."
exit
fi
fi
PASSWORD_SALT=$(pwgen -s 128 -N 1)
PASSWORD_SALTED=$PASSWORD$PASSWORD_SALT
PASSWORD_HASH=$(php /usr/lib/mocha/sql/php/hash_pw.php $PASSWORD_SALTED)
# these two commands SHOULD execute atomically
# BUT for some reason this doesn't work on initial provisioning of the vagrant vm
# ........ for some reason, it works just fine when run manually though...
# oh well, it's not like anything is going to happen in the few picoseconds between calls...
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "CALL mocha_set_attribute_value(mocha_get_user_by_username('$3'), mocha_get_instance_by_global_identifier('F377FC294DF14AFB96434191F37A00A9'), '$PASSWORD_HASH', NULL, NULL);" -e "CALL mocha_set_attribute_value(mocha_get_user_by_username('$3'), mocha_get_instance_by_global_identifier('8C5A99BC40ED4FA2B23FF373C1F3F4BE'), '$PASSWORD_SALT', NULL, NULL);" -e "CALL mocha_release_tenant();"
if [ $? -ne 0 ]; then
echo "mocha: password unchanged"
exit
fi
echo "mocha: password updated successfully"
exit
else
echo "usage: mocha oms user add|delete|lock|list|unlock|set-password"
fi
elif [ "$1" == "instance" ]; then
if [ "$2" == "list" ]; then
# usage: mocha oms instance list attributes INSTID
if [ "$3" == "" ]; then
$MOCHA_MYSQL -e "SELECT id, tenant_id, CONCAT(class_id, '$', inst_id) AS inst_key, global_identifier FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT')"
elif [ "$3" == "attributes" ]; then
if [ "$4" == "" ]; then
echo "usage: mocha oms instance list attributes INSTID"
exit
fi
# thanks https://stackoverflow.com/a/10520718
ATT_INST_ID=$4
ATT_INST_ID_CID=${ATT_INST_ID%\$*}
ATT_INST_ID_IID=${ATT_INST_ID#*\$}
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT * FROM mocha_attributes WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND src_inst_id = mocha_get_instance_by_key($ATT_INST_ID_CID, $ATT_INST_ID_IID);" -e "CALL mocha_release_tenant();"
fi
elif [ "$2" == "get" ]; then
if [ "$3" == "by-gid" ]; then
# thanks https://stackoverflow.com/a/911213
if [ -t 1 ]; then
$MOCHA_MYSQL -e "SELECT * FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND global_identifier = mocha_normalize_uuid('$4');"
else
$MOCHA_MYSQL -N -e "SELECT id FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND global_identifier = mocha_normalize_uuid('$4');"
fi
elif [ "$3" == "by-iid" ]; then
# thanks https://stackoverflow.com/a/10520718
INST_ID=$4
INST_ID_CID=${INST_ID%\$*}
INST_ID_IID=${INST_ID#*\$}
# thanks https://stackoverflow.com/a/911213
if [ -t 1 ]; then
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT * FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND class_id = $INST_ID_CID AND inst_id = $INST_ID_IID;" -e "CALL mocha_release_tenant();"
else
$MOCHA_MYSQL -N -e "SELECT id FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND class_id = $INST_ID_CID AND inst_id = $INST_ID_IID;"
fi
fi
fi
elif [ "$1" == "attribute" ]; then
if [ "$2" == "list" ]; then
REL_COLUMNS="id, tenant_id, mocha_get_instance_key(src_inst_id) AS source_inst, mocha_get_instance_key(att_inst_id) AS attribute_inst, att_value, mocha_get_instance_key(usr_inst_id) AS user_inst, att_effective_date"
# usage: mocha oms instance list attributes INSTID
if [ "$3" == "" ]; then
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT $REL_COLUMNS FROM mocha_attributes WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT');" -e "CALL mocha_release_tenant();"
elif [ "$3" == "for" ]; then
if [ "$4" == "" ]; then
echo "usage: mocha oms relationship list for INSTID"
exit
fi
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT $REL_COLUMNS FROM mocha_attributes WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND src_inst_id = $4;" -e "CALL mocha_release_tenant();"
fi
elif [ "$2" == "get" ]; then
if [ "$4" == "for" ]; then
ATT_ID=$3
INST_ID=$5
$MOCHA_MYSQL -N -s -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "CALL mocha_get_attribute_value($INST_ID, $ATT_ID, NULL);" -e "CALL mocha_release_tenant();"
fi
elif [ "$2" == "set" ]; then
if [ "$4" == "for" ]; then
# usage: `mocha oms attribute set (att) for (inst) (value)`
ATT_ID=$3
INST_ID=$5
ATT_VALUE=$6
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "CALL mocha_set_attribute_value($INST_ID, $ATT_ID, '$ATT_VALUE', NULL, NULL);" -e "CALL mocha_release_tenant();"
fi
fi
elif [ "$1" == "relationship" ]; then
if [ "$2" == "list" ]; then
REL_COLUMNS="id, tenant_id, mocha_get_instance_key(source_inst_id) AS source_inst, mocha_get_instance_key(relationship_inst_id) AS relationship_inst, mocha_get_instance_key(destination_inst_id) AS destination_inst, mocha_get_instance_key(user_inst_id) AS user_inst, effective_date"
# usage: mocha oms instance list attributes INSTID
if [ "$3" == "" ]; then
$MOCHA_MYSQL -e "SELECT $REL_COLUMNS FROM mocha_relationships WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT')"
elif [ "$3" == "for" ]; then
if [ "$4" == "" ]; then
echo "usage: mocha oms relationship list for INSTID"
exit
fi
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT $REL_COLUMNS FROM mocha_relationships WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND source_inst_id = $4;" -e "CALL mocha_release_tenant();"
fi
elif [ "$2" == "get" ]; then
if [ "$3" == "by-gid" ]; then
# thanks https://stackoverflow.com/a/911213
if [ -t 1 ]; then
$MOCHA_MYSQL -e "CALL mocha_select_tenant(mocha_get_tenant_by_name('$CURRENT_TENANT'));" -e "SELECT * FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND global_identifier = mocha_normalize_uuid('$4');" -e "CALL mocha_release_tenant();"
else
$MOCHA_MYSQL -N -e "SELECT id FROM mocha_instances WHERE tenant_id = mocha_get_tenant_by_name('$CURRENT_TENANT') AND global_identifier = mocha_normalize_uuid('$4');"
fi
fi
fi
else
echo "usage: mocha oms tenant|user|instance|attribute|relationship"
fi

View File

@ -0,0 +1,92 @@
#!/bin/bash
# mocha suv list
# mocha suv up
# mocha suv down
# mocha suv new
VAGRANT_MOCHADIR=/home/beckermj/Documents/Vagrant/mocha
VAGRANT_MACHINESDIR=$VAGRANT_MOCHADIR/machines
if [ "$1" == "list" ]; then
ls $VAGRANT_MACHINESDIR
elif [ "$1" == "up" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant up
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv up MACHINENAME"
fi
elif [ "$1" == "down" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant halt
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv down MACHINENAME"
fi
elif [ "$1" == "shell" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant ssh
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv shell MACHINENAME"
fi
elif [ "$1" == "delete" ]; then
if [ "$2" != "" ]; then
MACHINEPATH=$VAGRANT_MACHINESDIR/$2
if [ -d "$MACHINEPATH" ]; then
cd $MACHINEPATH
vagrant destroy
if [ "$?" == "0" ]; then
rm -rf $MACHINEPATH
fi
else
echo "unknown machine named $2"
fi
else
echo "usage: mocha suv delete MACHINENAME"
fi
elif [ "$1" == "new" ]; then
cd $VAGRANT_MOCHADIR
if [ "$2" == "--transient" ]; then
./provision --transient
else
./provision
fi
else
echo "usage: mocha suv new [--transient] | (up|down|shell|delete MACHINENAME) | list"
fi

View File

@ -0,0 +1,86 @@
#!/bin/bash
FIRSTRUN=0
if [ -f "/etc/mocha/username" ]; then
MOCHA_USERNAME=$(cat /etc/mocha/username)
MOCHA_PASSWORD=$(cat /etc/mocha/userpass)
else
# we are running for the first time (or we are transient)
HTML_HOME=/var/www/html
# reset the configuration file
cp /etc/mocha/include/Configuration.inc.php.template $HTML_HOME/include/Configuration.inc.php
# generate a not-very-secure but easily-rememberable password for zq-developer
MOCHA_USERNAME="zq-developer"
MOCHA_PASSWORD=$(pwgen -N 1)
if [ ! $? -eq 0 ]; then
echo ""
echo "could not generate a secure password, you may need to (re-)install pwgen"
echo ""
exit 3
fi
echo $MOCHA_USERNAME > /etc/mocha/username
echo $MOCHA_PASSWORD > /etc/mocha/userpass
MOCHA_DB_DATABASENAME="mocha_suv"
MOCHA_DB_USERNAME="mocha_suv"
# also generate a slightly more secure machine password for the mariadb database...
MOCHA_DB_PASSWORD=$(pwgen -s 32 -N 1)
# ... and add it to the configuration file
sed -i -e "s/@@MOCHA_DB_DATABASENAME@@/$MOCHA_DB_DATABASENAME/" -e "s/@@MOCHA_DB_USERNAME@@/$MOCHA_DB_USERNAME/" -e "s/@@MOCHA_DB_PASSWORD@@/$MOCHA_DB_PASSWORD/" $HTML_HOME/include/Configuration.inc.php
# ... and also add it to our local configuration
echo $MOCHA_DB_DATABASENAME > /etc/mocha/dbname
echo $MOCHA_DB_USERNAME > /etc/mocha/dbuser
echo $MOCHA_DB_PASSWORD > /etc/mocha/dbpass
# don't forget to make a backup
cp $HTML_HOME/include/Configuration.inc.php $HTML_HOME/include/Configuration.inc.php.bak
# create the MySQL database and user with the previously generated password
mysql -e "DROP DATABASE IF EXISTS $MOCHA_DB_DATABASENAME; DROP USER IF EXISTS $MOCHA_DB_USERNAME;"
mysql -e "CREATE DATABASE $MOCHA_DB_DATABASENAME; CREATE USER $MOCHA_DB_USERNAME IDENTIFIED BY '$MOCHA_DB_PASSWORD'; GRANT ALL ON $MOCHA_DB_DATABASENAME.* TO '$MOCHA_DB_USERNAME'@'%';"
# install mocha using the `mocha oms` command
mocha oms install
mocha oms install library /usr/share/mocha/libraries
mocha oms tenant select super
# set the new user name and password for the initial mocha user
mocha oms user set-password "$MOCHA_USERNAME" "$MOCHA_PASSWORD"
mocha oms tenant release
# record the initial start time for the SUV
echo $(date "+%Y-%m-%dT%H:%M:%S") > /etc/mocha/suvstart
chmod a+r /etc/mocha/suvstart
FIRSTRUN=1
fi
echo ""
echo "******************************************"
echo ""
echo "Thank you for provisioning your Mocha SUV!"
echo "You can log in with the following details:"
echo ""
echo "User name: $MOCHA_USERNAME"
echo "Password: $MOCHA_PASSWORD"
echo ""
echo "Your domain and IP address information is:"
echo ""
echo " $(hostname).privatesuv.com"
ip addr show dev enp0s8 | grep inet
echo ""
echo "******************************************"
echo ""
if [ $FIRSTRUN -eq 1 ]; then
# register the SUV for automatic shutdown in 10 hours
/usr/lib/mocha/spot_register_for_shutdown 600
fi

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "!!! This Spot Instance will automatically terminate in $1 minutes !!!"
shutdown -P +$1

View File

@ -47,16 +47,17 @@ fi
cd machines/$SUV_NAME
cp templates/$SUV_TEMPLATE/$SUV_TEMPLATE.Vagrantfile ./Vagrantfile
cp templates/$SUV_TEMPLATE/site.conf ./site.conf
cp common/certs/localhost.key .
cp common/certs/localhost.crt .
# ln -s templates/$SUV_TEMPLATE/mocha-libexec ./mocha-libexec
# cp templates/default/default.box ./default.box
ln -s ../mocha-mysql/mocha-mysql/src/mocha-mysql ./sql
ln -s ../mocha-php/mocha-php/src/mocha-php ./site
ln -s ../mocha-common/mocha-common/data/libraries ./libraries
ln -s ../mocha-common/mocha-common/data/uploads ./uploads
#! REMEMBER: we are in machines/$SUV_NAME now !
cp ../../templates/$SUV_TEMPLATE/$SUV_TEMPLATE.Vagrantfile ./Vagrantfile
cp ../../templates/$SUV_TEMPLATE/site.conf ./site.conf
cp ../../common/certs/localhost.key .
cp ../../common/certs/localhost.crt .
ln -s ../../common/libexec ./mocha-libexec
# cp ../../templates/default/default.box ./default.box
ln -s ../../../mocha-mysql/mocha-mysql/src/mocha-mysql ./sql
ln -s ../../../mocha-php/mocha-php/src/mocha-php ./site
ln -s ../../../mocha-common/mocha-common/data/libraries ./libraries
ln -s ../../../mocha-common/mocha-common/data/uploads ./uploads
echo "enter sudo password to add entry to /etc/hosts if desired"