def set_metadata(self, metadata): metadata = util.build_recursive(metadata) if 'Metadata' in metadata: metadata = metadata['Metadata'] self['Metadata'] = util.dict_merge(self.get('Metadata', {}), metadata) self.dirty_children()
def load(file, sections=[], **instargs): """Create a sMAP instance based on the representation stored in a file. The configuration file contains sections which refer to either reporting instances, or paths in the sMAP heirarchy. Any section whose name starts with ``/`` is treated as a resource name; sections starting with ``report`` are treated as reports. The file must contain at least one section named ``/``, which must contain a ``uuid`` key to set the root identifier for the source. :param string file: filename of the configuration file :param instargs: arguments passed to the :py:class:`~smap.core.SmapInstance` constructor. :return smap.core.SmapInstance: the created instancev :raise smap.loader.SmapLoadError: an error is encountered processing the file :raise smap.core.SmapError: some other error is encountered validating the loaded object """ found = None for l in ['', os.getcwd(), sys.prefix]: path = os.path.join(l, file) if os.path.isfile(path): found = path if not found: raise Exception("Config file %s not found." % file) print "Loading config file:", found conf = configobj.ConfigObj(found, indent_type=' ') # if there's a server section, override the default server # configuration with that if 'server' in conf: smapconf.SERVER = util.dict_merge(smapconf.SERVER, dict(((k.lower(), v) for (k, v) in conf['server'].iteritems()))) if 'logging' in conf: smapconf.LOGGING = util.dict_merge(smapconf.LOGGING, dict(((k.lower(), v) for (k, v) in conf['logging'].iteritems()))) # we need the root to have a uuid inst = core.SmapInstance(conf['/']['uuid'], **instargs) inst.loading = True reports = [] for s in conf: print "Loading section", s if s.startswith('report'): resource = conf[s].get('ReportResource', '/+') format = conf[s].get('Format', 'json') max_age = conf[s].get('MaxAge', None) max_age = int(max_age) if max_age != None else None dest = [conf[s]['ReportDeliveryLocation']] for i in xrange(0, 10): if 'ReportDeliveryLocation%i' % i in conf[s]: dest.append(conf[s]['ReportDeliveryLocation%i' % i]) reportinst = { 'ReportDeliveryLocation' : dest, 'ReportResource' : resource, 'Format': format, 'uuid' : inst.uuid(s), 'MaxAge' : max_age, } for o in ['MinPeriod', 'MaxPeriod']: if o in conf[s]: reportinst[o] = conf[s][o] for o in ['ClientCertificateFile', 'ClientPrivateKeyFile', 'CAFile']: if o in conf[s]: reportinst[i] = os.path.expanduser(conf[s][o]) reports.append(reportinst) continue elif not s.startswith('/'): # path sections must start with a '/' # other sections might be present and could be parsed by # other parts of the program print "Warning: skipping section", s, "since it does not begin with a '/'" continue elif len(sections) and not util.norm_path(s) in sections: # skip all but the listed sections if we were asked to continue s = util.norm_path(s) # build the UUID for the item props = util.build_recursive(dict(conf[s].items())) id = None if 'uuid' in conf[s]: key = None id = uuid.UUID(conf[s]['uuid']) elif 'key' in conf[s]: key = conf[s]['key'] else: # default to the path if key = s if key: id = inst.uuid(key) # raise SmapLoadError("Every config file section must have a uuid or a key!") # create the timeseries or collection if (s == '/' or conf[s].get("type", None) == 'Collection' or inst.get_collection(s) != None): if s == '/': c = inst.get_collection('/') elif inst.get_collection(s) != None: # sometimes you will have collections created twice, # for instance if a driver creates it and then we want # to tag it with metadata c = inst.get_collection(s) else: c = core.Collection(s, inst) inst.add_collection(s, c) elif conf[s].get("type", "Timeseries") == "Timeseries": if inst.get_timeseries(s) != None: c = inst.get_timeseries(s) else: try: props['Properties']['UnitofMeasure'] except KeyError: raise SmapLoadError("A Timeseries must have at least " "the Properites/UnitofMeasure key") # the Timeseries uses defaults if the conf file doesn't # contain the right sections. c = core.Timeseries(id, props['Properties']['UnitofMeasure'], data_type=props['Properties'].get('ReadingType', core.Timeseries.DEFAULTS['Properties/ReadingType']), timezone=props['Properties'].get('Timezone', core.Timeseries.DEFAULTS['Properties/Timezone']), buffersz=int(props.get('BufferSize', core.Timeseries.DEFAULTS['BufferSize']))) inst.add_timeseries(s, c) else: if not id: raise SmapLoadError("A driver must have a key or uuid to generate a namespace") # load a new driver manager layer newdrv = driver.SmapDriver.get_driver(inst, conf[s]['type'], s, id) # create a collection and add it at the attachment point c = inst.get_collection(s) if not c: c = core.Collection(s, inst) inst.add_collection(s, c) # Add config file specified checkers for the driver check = checkers.get(inst, newdrv, conf[s]) if check: inst.checkers.append(check) # get the driver to add its points newdrv.setup(conf[s]) # Metadata and Description are shared between both Collections # and Timeseries if props.has_key('Metadata'): # the driver may have added metadata; however config file # metadata overrides it c['Metadata'] = util.dict_merge(c.get('Metadata', {}), props['Metadata']) if props.has_key('Description'): c['Description'] = props['Description'] if key: setattr(c, 'key', key) # since the sections could come in any order, update the reporting # instance to make sure all the topics are set right. for reportinst in reports: if not inst.reports.update_report(reportinst): inst.reports.add_report(reportinst) inst.reports.update_subscriptions() inst.loading = False return inst
def load(file, sections=[], **instargs): """Create a sMAP instance based on the representation stored in a file. The configuration file contains sections which refer to either reporting instances, or paths in the sMAP heirarchy. Any section whose name starts with ``/`` is treated as a resource name; sections starting with ``report`` are treated as reports. The file must contain at least one section named ``/``, which must contain a ``uuid`` key to set the root identifier for the source. :param string file: filename of the configuration file :param instargs: arguments passed to the :py:class:`~smap.core.SmapInstance` constructor. :return smap.core.SmapInstance: the created instancev :raise smap.loader.SmapLoadError: an error is encountered processing the file :raise smap.core.SmapError: some other error is encountered validating the loaded object """ found = None for l in ['', os.getcwd(), sys.prefix]: path = os.path.join(l, file) if os.path.isfile(path): found = path if not found: raise Exception("Config file %s not found." % file) print "Loading config file:", found conf = configobj.ConfigObj(found, indent_type=' ') # if there's a server section, override the default server # configuration with that if 'server' in conf: smapconf.SERVER = util.dict_merge( smapconf.SERVER, dict(((k.lower(), v) for (k, v) in conf['server'].iteritems()))) # we need the root to have a uuid inst = core.SmapInstance(conf['/']['uuid'], **instargs) inst.loading = True reports = [] for s in conf: print "Loading section", s if s.startswith('report'): resource = conf[s].get('ReportResource', '/+') format = conf[s].get('Format', 'json') max_age = conf[s].get('MaxAge', None) max_age = int(max_age) if max_age != None else None dest = [conf[s]['ReportDeliveryLocation']] for i in xrange(0, 10): if 'ReportDeliveryLocation%i' % i in conf[s]: dest.append(conf[s]['ReportDeliveryLocation%i' % i]) reportinst = { 'ReportDeliveryLocation': dest, 'ReportResource': resource, 'Format': format, 'uuid': inst.uuid(s), 'MaxAge': max_age, } for o in ['MinPeriod', 'MaxPeriod']: if o in conf[s]: reportinst[o] = conf[s][o] for o in [ 'ClientCertificateFile', 'ClientPrivateKeyFile', 'CAFile' ]: if o in conf[s]: reportinst[i] = os.path.expanduser(conf[s][o]) reports.append(reportinst) continue elif not s.startswith('/'): # path sections must start with a '/' # other sections might be present and could be parsed by # other parts of the program print "Warning: skipping section", s, "since it does not begin with a '/'" continue elif len(sections) and not util.norm_path(s) in sections: # skip all but the listed sections if we were asked to continue s = util.norm_path(s) # build the UUID for the item props = util.build_recursive(dict(conf[s].items())) id = None if 'uuid' in conf[s]: key = None id = uuid.UUID(conf[s]['uuid']) elif 'key' in conf[s]: key = conf[s]['key'] else: # default to the path if key = s if key: id = inst.uuid(key) # raise SmapLoadError("Every config file section must have a uuid or a key!") # create the timeseries or collection if (s == '/' or conf[s].get("type", None) == 'Collection' or inst.get_collection(s) != None): if s == '/': c = inst.get_collection('/') elif inst.get_collection(s) != None: # sometimes you will have collections created twice, # for instance if a driver creates it and then we want # to tag it with metadata c = inst.get_collection(s) else: c = core.Collection(s, inst) inst.add_collection(s, c) elif conf[s].get("type", "Timeseries") == "Timeseries": if inst.get_timeseries(s) != None: c = inst.get_timeseries(s) else: try: props['Properties']['UnitofMeasure'] except KeyError: raise SmapLoadError("A Timeseries must have at least " "the Properites/UnitofMeasure key") # the Timeseries uses defaults if the conf file doesn't # contain the right sections. c = core.Timeseries( id, props['Properties']['UnitofMeasure'], data_type=props['Properties'].get( 'ReadingType', core.Timeseries.DEFAULTS['Properties/ReadingType']), timezone=props['Properties'].get( 'Timezone', core.Timeseries.DEFAULTS['Properties/Timezone']), buffersz=int( props.get('BufferSize', core.Timeseries.DEFAULTS['BufferSize']))) inst.add_timeseries(s, c) else: if not id: raise SmapLoadError( "A driver must have a key or uuid to generate a namespace") # load a new driver manager layer newdrv = driver.SmapDriver.get_driver(inst, conf[s]['type'], s, id) # create a collection and add it at the attachment point c = inst.get_collection(s) if not c: c = core.Collection(s, inst) inst.add_collection(s, c) # Add config file specified checkers for the driver check = checkers.get(inst, newdrv, conf[s]) if check: inst.checkers.append(check) # get the driver to add its points newdrv.setup(conf[s]) # Metadata and Description are shared between both Collections # and Timeseries if props.has_key('Metadata'): # the driver may have added metadata; however config file # metadata overrides it c['Metadata'] = util.dict_merge(c.get('Metadata', {}), props['Metadata']) if props.has_key('Description'): c['Description'] = props['Description'] if key: setattr(c, 'key', key) # since the sections could come in any order, update the reporting # instance to make sure all the topics are set right. for reportinst in reports: if not inst.reports.update_report(reportinst): inst.reports.add_report(reportinst) inst.reports.update_subscriptions() inst.loading = False return inst