def get(self, name): # lookup user's auth info user_info = User.get_by_id(long(self.user_id)) # look up user's instances instance = Instance.get_by_name(name) self.response.headers['Content-Type'] = "text/plain" if not instance: params = {"contents": "Waiting on serial console output..."} return self.render_template('instance/console.txt', **params) try: # update list of instances we have http = httplib2.Http() url = '%s/api/instance/%s/console?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) response, content = http.request(url, 'GET') stuff = json.loads(content) params = {"contents": stuff['contents']} except Exception as ex: params = {"contents": "Waiting on serial console output..."} return self.render_template('instance/console.txt', **params)
def get(self, instance_name = None): # get the instance, build the response type instance = Instance.get_by_name(instance_name) self.response.headers['Content-Type'] = "application/json" # if no instance, then show error if not instance: params['message'] = "Instance not found." self.response.set_status(404) return self.render_template('api/response.json', **params) # load the instance's meta data, if any if instance.meta: meta = json.loads(instance.meta) else: meta = json.loads('{}') # build response params = { "instance": instance, "meta": meta } params['response'] = "success" self.response.headers['Content-Type'] = 'application/json' return self.render_template('api/instance.json', **params)
def get(self, name=None): # check token token = self.request.get('token') if token != "": user_info = User.get_by_token(token) if user_info: instance = Instance.get_by_name(name) try: if instance.user == user_info.key: # make the instance call to the control box http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/start?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) # pull the response back TODO add error handling response, content = http.request(url, 'GET', None, headers={}) # update if google returns pending if json.loads(content)['status'] == "PENDING": instance.status = "STAGING" instance.started = datetime.datetime.now() instance.put() params = {'instance': instance} self.response.headers[ 'Content-Type'] = "application/json" return self.render_template('api/instance.json', **params) except Exception as ex: print "error %s" % ex print "instance %s not found or not in TERMINATED state" % name params = { "response": "fail", "message": "[token] read access denied or instance not TERMINATED" } return self.render_template('api/response.json', **params) # no token, no user, no data params = { "response": "fail", "message": "must include [token] parameter with a valid token" } self.response.status = '402 Payment Required' self.response.status_int = 402 self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params)
def get(self, name): # lookup user's auth info user_info = User.get_by_id(long(self.user_id)) # look up user's instances instance = Instance.get_by_name(name) if not instance: params = {} return self.redirect_to('instances-list', **params) if instance.renamed == None: instance.renamed = "" # remap so template can address if instance.created < (datetime.datetime.now() - datetime.timedelta(0, 600)): instance.expired = True else: instance.expired = False stream = Stream.get_by_id(instance.stream.id()) if utils.read_cookie(self, "guide") == "closed": guide = False else: guide = True if instance.size == 1: instance_cores = 8 instance_memory = 30 elif instance.size == 2: instance_cores = 16 instance_memory = 60 else: instance_cores = 4 instance_memory = 15 params = { 'guide': guide, 'instance': instance, 'stream': stream, 'user_info': user_info, 'instance_cores': instance_cores, 'instance_memory': instance_memory } return self.render_template('instance/detail.html', **params)
def get(self, instance_name = None): # get the instance, build the response type instance = Instance.get_by_name(instance_name) self.response.headers['Content-Type'] = "application/json" # if no instance, then show error if not instance: params['message'] = "Instance not found." self.response.set_status(404) return self.render_template('api/response.json', **params) params = {} params['response'] = "success" self.response.headers['Content-Type'] = 'application/json' return self.render_template('api/instance.json', **params)
def get(self, name=None): # check token token = self.request.get('token') if token != "": user_info = User.get_by_token(token) if user_info: instance = Instance.get_by_name(name) try: if instance.user == user_info.key: params = {'instance': instance} self.response.headers[ 'Content-Type'] = "application/json" return self.render_template('api/instance.json', **params) except Exception as ex: print "error %s" % ex print "instance %s not found" % name params = { "response": "fail", "message": "[token] read access denied" } return self.render_template('api/response.json', **params) # no token, no user, no data params = { "response": "fail", "message": "must include [token] parameter with a valid token" } self.response.status = '402 Payment Required' self.response.status_int = 402 self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params)
def get(self, name, command): # lookup user's auth info user_info = User.get_by_id(long(self.user_id)) # get instance instance = Instance.get_by_name(name) if not instance: params = {} return self.redirect_to('instances-list', **params) slack.slack_message( "request for an instance we can't find - SPAMSPAMSPAM") else: # check user owns it or user is admin if user_info.admin != True and long(instance.user.id()) != long( self.user_id): params = { "response": "failure", "message": "instance %s not modifiable by calling user" % name } self.response.set_status(500) slack.slack_message("%s doesn't own %s" % (user_info.username, name)) else: # start the instance if command == "start" and instance.status != "RUNNING": slack.slack_message("firing up %s" % instance.name) try: instance.started = datetime.datetime.now() instance.tender_action = "START" instance.put() params = { "response": "success", "message": "Instance %s marked to be started." % instance.name } slack.slack_message( "updated db for %s with %s" % (instance.name, instance.tender_action)) except Exception as ex: params = {"response": "failure", "message": "%s" % ex} self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params) # add ssh_key to instance elif command == "addkey": # make the instance call to the control box http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/addkey?token=%s&ssh_key=%s&username=%s' % ( config.fastener_host_url, name, config.fastener_api_token, urllib.quote(user_info.ssh_key), user_info.username) try: # pull the response back TODO add error handling response, content = http.request(url, 'GET', None, headers={}) # delete if google returns pending if json.loads(content)['status'] == "SUCCESS": params = { "response": "success", "message": "instance %s updated with key" % name } else: params = { "response": "failure", "message": "instance %s operation failure" % name } response.set_status(500) except: params = { "response": "failure", "message": "instance %s failure" % name } self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params) # just the status elif command == "status": params = {"instance": instance} self.response.headers['Content-Type'] = "application/json" return self.render_template('api/instance.json', **params) # delete the instance - C'est la vie elif command == "delete": instance.key.delete() # let the tender script delete it params = { "response": "success", "message": "Instance marked to be deleted." } self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params) # rename it elif command == "rename": renamed = self.request.get('renamed') instance.renamed = renamed instance.put() params = {"instance": instance} self.response.headers['Content-Type'] = "application/json" return self.render_template('api/instance.json', **params) else: params = { "response": "failure", "message": "bad command, skippy" } self.response.set_status(500) self.response.headers['Content-Type'] = "application/json" return self.render_template('api/response.json', **params)
def get(self): try: # grab a list of instances from the Fastener API http = httplib2.Http(timeout=30) url = '%s/api/instance/list?token=%s' % (config.fastener_host_url, config.fastener_api_token) response, content = http.request(url, 'GET') # list of instances from Google Cloud (see ./fastener/sample-output.json) gcinstances = json.loads(content) if len(gcinstances) > 0: message = "ok" else: message = "no instances were returned from fastener API" except Exception as ex: gcinstances = [] slack.slack_message( "Tender::Exception with list query to fastener box.") message = "failed to contact fastener API" # list of instances from db instances = Instance.get_all() # bail if we didn't get any instances from Google if len(gcinstances) == 0: params = { "message": message, "gc_count": len(gcinstances), "db_count": len(instances) } slack.slack_message("Tender::No instances from Google?") self.response.headers['Content-Type'] = "application/json" return self.render_template('api/tender.json', **params) ###### # loop through list of instances in local or production DB for instance in instances: name = instance.name found = False # loop through the instances we got from google for gcinstance in gcinstances: # check if the names match if name == gcinstance['name']: # got a match found = True try: # grab the IP address and status instance.ip = gcinstance['networkInterfaces'][0][ 'accessConfigs'][0]['natIP'] except: # got limited or no data about instance instance.ip = "None" # leave commented out slack.slack_message("Tender::%s has status %s" % (instance.name, instance.status)) # if not BUILDING then update status right from google if instance.status not in ("BUILDING"): instance.status = gcinstance['status'] # at this point if the instance.status is NOT BUILDING, then we grab # whatever google says the instance is doing. if it's RUNNING, then # we do an instance link test to ensure the fusion service is running # if Fusion does not respond, we set it to CONFIGURING # BUILDING state is kept until an update of BUILDING state is done # see APIs # are we running? if instance.status == "RUNNING": # check if the box is running fusion admin yet (CONFIGURING if NOT) try: # fast fail connection for checking if fusion is up http_test = httplib2.Http(timeout=2) test_url = 'http://%s:8764' % instance.ip response, content = http_test.request( test_url, 'GET') test_status = response['status'] except: slack.slack_message( "Tender::%s FAILED Fusion port test." % (instance.name)) test_status = "404" # set admin_link if box is running and test comes back 200 if test_status == "200": instance.admin_link = test_url # build app link and update, if it exists try: if instance.stream.get().app_stub: app_stub = instance.stream.get().app_stub instance.app_link = "http://%s%s" % ( instance.ip, app_stub) else: instance.app_link = None except: instance.app_link = None else: # show the box is in CONFIGURING instance.status = "CONFIGURING" instance.admin_link = None instance.app_link = None instance.put() else: # NOT RUNNING STATUS (FROM GOOGLE) OR BUILDING (FROM DEPLOY SCRIPT) # should we start it? if instance.tender_action == "START": # try to start it http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/start?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) try: # pull the response back TODO add error handling response, content = http.request(url, 'GET', None, headers={}) # update if google returns pending if json.loads(content)[ 'status'] == "PENDING" or json.loads( content)['status'] == "DONE": params = { "response": "success", "message": "instance %s started" % name } instance.status = "PROVISIONING" instance.tender_action = "NONE" instance.started = datetime.datetime.now() instance.put() slack.slack_message( "Tender::%s wanted and got a START" % (instance.name)) else: slack.slack_message( "Tender::%s wanted START but google reported %s" % (instance.name, json.loads(content)['status'])) except Exception as ex: slack.slack_message( "Tender::Exception %s with %s" % (ex, instance.name)) else: # slack.slack_message("Tender::%s not requesting any actions." % instance.name) pass # instance has been terminated if instance.status == "TERMINATED": # set start time to far in the past instance.started = instance.created - datetime.timedelta( 0, 604800) # make sure we write all changes out instance.put() break # no need to keep looking else: # instance doesn't match the one we're working on pass if not found: # box wasn't found on GCP (via fastener LIST call) slack.slack_message( "Instance %s noted not being on GCP - looking" % name) http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/status?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) # pull the response back response, content = http.request(url, 'GET', None, headers={}) result = json.loads(content) if not result: # we could not verify box was or wasn't running (fastener might not be running) slack.slack_message("Can't tell what is going on.") pass else: try: if result['error'] == "NOTFOUND": slack.slack_message( "Deleting instance %s from DB for not being on GCP." % name) instance.key.delete() except: # no error # why are we here, we got a response this box is running pass else: # no instances in db pass # cleanup stray and EOL instances for gcinstance in gcinstances: instance = Instance.get_by_name(gcinstance['name']) if instance: name = instance.name # if instance is expired, end it if instance.expires < datetime.datetime.now(): # make the instance call to the control box try: http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/delete?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) # pull the response back response, content = http.request(url, 'GET', None, headers={}) if content['status'] == "PENDING": instance.key.delete() slack.slack_message( "DELETING instance %s's from GCP because expired." % name) except: slack.slack_message( "ERROR: failed deleting instance %s's from GCP because expired." % name) else: # instance wasn't found in db name = gcinstance['name'] # make sure we don't delete non-demo or prod instances if 'button' in name and config.isdev == False: # i.e. put 'button' in an instance name & this will delete the instance slack.slack_message( "Not found in DB. Will try to delete instance %s's from Google Cloud." % name) # make the instance call to the control box # THIS IS THE DANGEROUS BITS try: http = httplib2.Http(timeout=10) url = '%s/api/instance/%s/delete?token=%s' % ( config.fastener_host_url, name, config.fastener_api_token) # pull the response back response, content = http.request(url, 'GET', None, headers={}) if content['status'] == "PENDING": slack.slack_message( "DELETING instance %s's from Google Cloud." % name) else: slack.slack_message( "ERROR: funky content returned while deleting instance %s's from Google Cloud." % name) except: slack.slack_message( "ERROR: failed deleting instance %s from Google Cloud." % name) else: # no instances from cloud - this should never run pass params = { "message": message, "gc_count": len(gcinstances), "db_count": len(instances) } self.response.headers['Content-Type'] = "application/json" return self.render_template('api/tender.json', **params)
def put(self, instance_name = None): # disable csrf check in basehandler csrf_exempt = True # paramters, assume failure, response type params = {} params['response'] = "error" self.response.headers['Content-Type'] = "application/json" # get the instance, build the response type instance = Instance.get_by_name(instance_name) self.response.headers['Content-Type'] = "application/json" # if no instance, then show error if not instance: params['message'] = "Instance not found." self.response.set_status(404) return self.render_template('api/response.json', **params) else: # load the instance's meta data, if any if instance.meta: meta = json.loads(instance.meta) else: meta = json.loads('{}') # load the json from the call try: body = json.loads(self.request.body) # loop through key space and set meta data for key in body: meta[key] = body[key] # dump back into the db instance.meta = json.dumps(meta) instance.put() except Exception as e: params['message'] = "An error was encountered with parsing meta key values: %s." % str(e) self.response.set_status(500) return self.render_template('api/response.json', **params) # send update information to channel if instance.token: output = { "name": instance.name, "token": instance.token, "state": instance.state, "meta": meta } channel.send_message(instance.token, json.dumps(output)) # build response params = { "instance": instance, "meta": json.loads(instance.meta) } params['response'] = "success" self.response.headers['Content-Type'] = 'application/json' return self.render_template('api/instance.json', **params)