def DELETE(self): """ Delete models for multiple instances :: DELETE /_instances DELETE data: :: [ "{region}/{namespace}/{instanceId}", ... ] Returns: :: { "result": "success" } """ try: instances = json.loads(web.data()) except: raise InvalidRequestResponse({"result": "Invalid request"}) if not instances: raise InvalidRequestResponse({"result": ("Missing instances in DELETE" " request")}) deleted = [] if instances: for server in instances: if server.count("/") == 4: (lhs, _, identifier) = server.rpartition("/") (regionAndNamespace, _, _) = lhs.rpartition("/") serverSansDimension = regionAndNamespace + "/" + identifier else: serverSansDimension = server with web.ctx.connFactory() as conn: modelIds = repository.listMetricIDsForInstance(conn, serverSansDimension) if modelIds: for modelId in modelIds: ModelHandler.deleteModel(modelId) deleted.append(server) if instances == deleted: self.addStandardHeaders() return encodeJson({'result': 'success'}) raise web.notfound("Not able to delete %s" % encodeJson(list(set(instances)-set(deleted))))
def GET(self): """ Get all instances :: GET /_instances Sample Output: :: [ { "location": "us-west-2", "message": null, "name": "jenkins-master", "namespace": "AWS/EC2", "server": "i-12345678", "status": 2 "parameters": { "region": "us-west-2", "AutoScalingGroupName": "htm-itsolutions-com-ssl" }, }, ... ] """ with web.ctx.connFactory() as conn: instances = repository.getInstances(conn) # To support idempotency requirements of the web ui, ensure that server # parameter matches the same pattern as is required for POST, and DELETE. # This means inserting the dimension between the namespace and identifier # for AWS-only. Autostacks are ignored here. for instance in instances: if "/AWS/" in instance["server"]: dimensions = instance["parameters"]["metricSpec"]["dimensions"] for (dimension, value) in dimensions.iteritems(): if instance["server"].endswith("/" + value): # We're looking for the identifying dimension in the instance # parameters (lhs, _, identifier) = (instance["server"].rpartition("/")) instance["server"] = "/".join([lhs, dimension, identifier]) if instance["message"] is "": instance["message"] = None self.addStandardHeaders() return encodeJson(instances)
def POST(self): # pylint: disable=R0201,C0103 """ Handles calls from clients for messages. Expects to received batched requests, keyed by the name of the template used to identify responses. """ global messageManager # pylint: disable=W0603 data = web.input() messagesOut = {} if htm-it.app.DEBUG_LEVEL > 0: # When debugging, read the file and create new MessageManager on # every request so we can change messages.json on the fly. with open(os.path.join(htm-it.app.HTM-IT_HOME, "resources/messages/us/messages.json")) as f: messageManager = messagemanager.MessageManager(f.read()) # Make sure we have the latest version of configuration htm-it.app.config.loadConfig() for templateKey in data: templateLocation = data[templateKey] if templateKey == "explicit": # The templateKey is either an id or the string "explicit", which means # that the client wants to identify the key directly, not by template, # which is easy enough. for templateId in templateLocation.split(","): messagesOut[templateId] = messageManager.getMessagesByKey(templateId) else: # To get the right relative lookup path for messages.json, we"ll # remove known template paths. baseUrl = htm-it.app.config.get("web", "base_url") path = templateLocation\ .replace(baseUrl + "/static/js/program/templates/", "") msgs = messageManager.getMessagesForTemplate(path) messagesOut[templateKey] = msgs web.header("Content-Type", "application/json; charset=UTF-8", True) return encodeJson(messagesOut)
def POST(self): # pylint: disable=C0103 data = jsonDecode(web.data()) htm-it.app.config.loadConfig() # if they already authed, new aws creds must match the originals if htm-it.app.config.has_section("aws"): if htm-it.app.config.has_option("aws", "aws_access_key_id"): awsAccessKeyId = htm-it.app.config.get("aws", "aws_access_key_id") if awsAccessKeyId and awsAccessKeyId != data["aws_access_key_id"]: raise UnauthorizedResponse({ "result": ("Please use the same AWS Credentials that you " "initially authenticated with.") }) try: checkEC2Authorization(data["aws_access_key_id"], data["aws_secret_access_key"]) except (AuthFailure, AWSPermissionsError) as e: raise UnauthorizedResponse({"result": str(e)}) result = {"result": "success"} apikey = None if htm-it.app.config.has_section("security"): if htm-it.app.config.has_option("security", "apikey"): apikey = htm-it.app.config.get("security", "apikey") if not apikey: apikey = self.generateAPIKey() htm-it.app.config.set("security", "apikey", apikey) htm-it.app.config.save() result["apikey"] = apikey web.header("Content-Type", "application/json; charset=UTF-8", True) return encodeJson(result)
def POST(self, region, namespace, instanceId=None): """ Monitor a set of default metrics for a specific instance :: POST /_instances/{region}/{namespace}/{instanceId} Returns: :: { "result": "success" } OR Monitor a set of default metrics for multiple specific instances :: POST /_instances/{region}/{namespace} POST data: :: [ {instanceId}, ... ] Returns: :: { "result": "success" } Note: We expect a 200 OK even when attempting to POST to an instanece in the wrong namespace or the wrong region, this saves the overhead of asking AWS if we're dealing with a valid instance in the given namespace or region with every POST request. We expect the CLI user to know the correct instance ID. """ if instanceId is None: try: dimension = None instances = json.loads(web.data()) except: raise InvalidRequestResponse({"result": "Invalid request"}) else: (dimension, _, identifier) = instanceId.rpartition("/") instances = [identifier] # Check for invalid region or namespace cwAdapter = datasource.createDatasourceAdapter("cloudwatch") supportedRegions = set(region for region, _desc in cwAdapter.describeRegions()) if region not in supportedRegions: raise InvalidRequestResponse({"result": ("Not supported. Region '%s' was" " not found.") % region}) supportedNamespaces = set() for resourceInfo in cwAdapter.describeSupportedMetrics().values(): for metricInfo in resourceInfo.values(): supportedNamespaces.add(metricInfo["namespace"]) if namespace not in supportedNamespaces: raise InvalidRequestResponse({"result": ("Not supported. Namespace '%s' " "was not found.") % namespace}) try: # Attempt to validate instances list using validictory validate(instances, _INSTANCES_MODEL_CREATION_SCHEMA) except ValidationError as e: response = "InvalidArgumentsError: " + str(e) raise InvalidRequestResponse({"result": response}) if instances: for instanceId in instances: server = "/".join([region, namespace, instanceId]) with web.ctx.connFactory() as conn: numMetrics = repository.getMetricCountForServer(conn, server) if numMetrics > 0: # Metrics exist for instance id. pass else: try: resourceType = cloudwatch.NAMESPACE_TO_RESOURCE_TYPE[namespace] except KeyError: raise InvalidRequestResponse({"result": "Not supported."}) modelSpecs = cwAdapter.getDefaultModelSpecs( resourceType, region, instanceId, dimension) for modelSpec in modelSpecs: ModelHandler.createModel(modelSpec) self.addStandardHeaders() return encodeJson({"result": "success"})
def GET(self, region=None): # pylint: disable=R0201 """ Get quick selection instance suggestions to monitor :: GET /_instances/suggestions Sample Output: :: { "suggested": [ { "region": "us-west-2", "namespace": "AWS/EC2", "id": "i-12345678" }, ... (up to 8 total suggested) ... ], "alternates": [ { "region": "us-west-2", "namespace": "AWS/ELB", "id": "htm-it-docs-elb" }, ... (up to 22 total alternatives) ... ] } """ if region is None: region = config.get("aws", "default_region") ec2Queue = Queue.Queue() ec2Thread = threading.Thread( target=ec2_utils.getSuggestedInstances, args=(region, ec2Queue, _AWS_INSTANCE_FETCHING_TIME_LIMIT)) ec2Thread.start() rdsQueue = Queue.Queue() rdsThread = threading.Thread( target=rds_utils.getSuggestedInstances, args=(region, rdsQueue, _AWS_INSTANCE_FETCHING_TIME_LIMIT)) rdsThread.start() elbQueue = Queue.Queue() elbThread = threading.Thread( target=elb_utils.getSuggestedInstances, args=(region, elbQueue, _AWS_INSTANCE_FETCHING_TIME_LIMIT)) elbThread.start() asgQueue = Queue.Queue() asgThread = threading.Thread( target=asg_utils.getSuggestedInstances, args=(region, asgQueue, _AWS_INSTANCE_FETCHING_TIME_LIMIT)) asgThread.start() response = { "suggested": [], "alternates": [], } # Wait for the threads to finish ec2Thread.join() rdsThread.join() elbThread.join() asgThread.join() n = 0 done = False while n < _MAX_SUGGESTED_INSTANCES_TOTAL and not done: done = True # EC2 Instances try: instance = ec2Queue.get(block=False) if n < _NUM_SUGGESTED_INSTANCES: response["suggested"].append(instance) else: response["alternates"].append(instance) done = False n += 1 if n >= _MAX_SUGGESTED_INSTANCES_TOTAL: break except Queue.Empty: pass # RDS Instances try: instance = rdsQueue.get(block=False) if n < _NUM_SUGGESTED_INSTANCES: response["suggested"].append(instance) else: response["alternates"].append(instance) done = False n += 1 if n >= _MAX_SUGGESTED_INSTANCES_TOTAL: break except Queue.Empty: pass # Load Balancers try: instance = elbQueue.get(block=False) if n < _NUM_SUGGESTED_INSTANCES: response["suggested"].append(instance) else: response["alternates"].append(instance) done = False n += 1 if n >= _MAX_SUGGESTED_INSTANCES_TOTAL: break except Queue.Empty: pass # AutoScaling groups try: instance = asgQueue.get(block=False) if n < _NUM_SUGGESTED_INSTANCES: response["suggested"].append(instance) else: response["alternates"].append(instance) done = False n += 1 if n >= _MAX_SUGGESTED_INSTANCES_TOTAL: break except Queue.Empty: pass return encodeJson(response)
def getData(latitude, longitude): SqlData = getSqlData(latitude, longitude) jsonData = encodeJson(SqlData) return jsonData