def trashman(self): from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_decommission # build the response response = {"response": "success", "result": {"message": "", "server": {}}} # get instance (server) info cluster_response = instance_info(self) if cluster_response['response'] == "success": # we should NOT have this, so try to decomission out of desperation cluster_response = instance_decommission(self) response['result']['message'] = "Terminating instance %s" % self.name else: # delete this instance into forever address = Addresses().get_by_id(self.address_id) address.release() self.delete(self) response['result']['message'] = "Instance %s has been deleted." % self.name # make a call to the callback url to report instance details appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def reserve(self, callback_url, flavor_id): # build response response = {"response": "success", "result": {"message": ""}} # find a willing instance instance = db.session.query(Instances).filter_by( state=1, flavor_id=flavor_id).first() if instance: # set that instance to reserved (active == 10) instance.state = 10 instance.callback_url = callback_url instance.update() # tell the pool we're using it (url must be empty string to tell pool) appliance = Appliance().get() pool_response = pool_instance(url="", instance=self, appliance=appliance) # response response['result'][ 'message'] = "Instance %s marked as reserved." % instance.name response['result']['instance'] = row2dict(instance) response['result']['ask'] = instance.flavor.ask response['result']['address'] = instance.address.address else: response['response'] = "error" response['result']['message'] = "No available instances." return response
def reserve(self, callback_url, flavor_id): # build response response = {"response": "success", "result": {"message": ""}} # find a willing instance instance = db.session.query(Instances).filter_by(state=1, flavor_id=flavor_id).first() if instance: # set that instance to reserved (active == 10) instance.state = 10 instance.callback_url = callback_url instance.update() # tell the pool we're using it (url must be empty string to tell pool) appliance = Appliance().get() pool_response = pool_instance(url="", instance=self, appliance=appliance) # response response['result']['message'] = "Instance %s marked as reserved." % instance.name response['result']['instance'] = row2dict(instance) response['result']['ask'] = instance.flavor.ask response['result']['address'] = instance.address.address else: response['response'] = "error" response['result']['message'] = "No available instances." return response
def trashman(self): from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_decommission # build the response response = { "response": "success", "result": { "message": "", "server": {} } } # get instance (server) info cluster_response = instance_info(self) if cluster_response['response'] == "success": # we should NOT have this, so try to decomission out of desperation cluster_response = instance_decommission(self) response['result'][ 'message'] = "Terminating instance %s" % self.name else: # delete this instance into forever address = Addresses().get_by_id(self.address_id) address.release() self.delete(self) response['result'][ 'message'] = "Instance %s has been deleted." % self.name # make a call to the callback url to report instance details appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def housekeeping(self): from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_suspend from webapp.libs.openstack import instance_resume from webapp.libs.openstack import instance_decommission from webapp.libs.openstack import instance_console # build the response response = {"response": "success", "result": {"message": "", "server": {}}} # get instance (server) info cluster_response = instance_info(self) server = cluster_response['result']['server'] # we all have limited time in this reality epoch_time = int(time.time()) # set start state start_state = self.state # this is complicated...because we aren't EC with OpenStack...or I'm crazy if cluster_response['response'] == "success": # openstack responded it found this instance if server.status == "ACTIVE": # openstack says the server is running if self.expires < epoch_time: # suspend the instance for non-payment response = instance_suspend(self) response['result']['message'] = "Instance %s suspended." % self.name self.state = 5 elif self.expires > epoch_time: # openstack says we're running, and we're paid if self.state == 5 or self.state == 6: # we move the instance to starting mode response['result']['message'] = "Instance %s is starting." % self.name self.state = 3 elif server.status == "SUSPENDED": # openstack says this instance is suspended if self.expires > epoch_time: # should be running because not expired response = instance_resume(self) response['result']['message'] = "Instance %s resumed." % self.name self.state = 3 # mark as starting if self.expires + app.config['POOL_DECOMMISSION_TIME'] < epoch_time: # should be destroyed (suspended for +2 hours without pay) response['result']['message'] = "Instance %s decommissioned." % self.name self.state = 7 else: # openstack indicates another state besides SUSPENDED or ACTIVE if self.expires > epoch_time: # we should be running, but in a weird state - destroy then restart response = instance_decommission(self) response['result']['message'] = "Instance %s restarted." % self.name self.state = 2 # set as paid and ready to start app.logger.error("OpenStack says instance=(%s) isn't in the correct state. Setting to restart." % self.name) else: # expired but in a weird state - destroy response = instance_decommission(self) response['result']['message'] = "Instance %s decommissioned." % self.name self.state = 7 else: # openstack can't find this instance if self.expires > epoch_time: if self.state == 2: # check error rate if self.message_count > 10: # we're failing to start the instance, so decomission response['result']['message'] = "Instance %s decommissioned." % self.name self.state = 7 app.logger.error("Exceeded error rate on callbacks for instance=(%s). Decomissioning." % self.name) else: # set instance to restart - not expired, should be running response['response'] = "error" # technically, someone is probably f*****g with things response['result']['message'] = "Setting instance %s to restart." % self.name self.state = 2 # will be started shortly after this by start app.logger.error("OpenStack doesn't know about instance=(%s). Setting to restart." % self.name) else: # no reason to be running response['response'] = "error" response['result']['message'] = "Instance %s decommissioned." % self.name self.state = 7 # will be deleted shortly after this by trashman # get instance console output cluster_response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] # update self.update() # make a call to the callback url to report instance details on state change if self.state != start_state: appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def nudge(self): from webapp.libs.openstack import try_associate_floating_ip from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_console from webapp.libs.openstack import instance_decommission # get instance console output response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] self.update() # get instance (server) info response = instance_info(self) # set start state start_state = self.state # set instance meta data if response['response'] == "success": server = response['result']['server'] # if the state is ACTIVE, we set to be running state==4 if server.status == "ACTIVE": # set network info self.state = 4 # try to get a floating ip for the new server float_response = try_associate_floating_ip(server) # check if call got a floating IP if float_response['response'] == "success": # get instance info again to pick up new IP response = instance_info(self) # load the response into the server object if response['response'] == "success": server = response['result']['server'] else: # log 'errors' in floating assignment app.logger.info(float_response['result']['message']) # extract IP addresses using IPy # in some circumstances this will squash multiple same/same address types # we only extract and store one each of private ipv4, public ipv4, and public ipv6 for key in server.networks.keys(): # any network names for address in server.networks[key]: # loop through each address for each network # private IPv4 if IP(address).iptype() == "PRIVATE" and IP(address).version() == 4: self.privateipv4 = address # public IPv4 elif IP(address).iptype() == "PUBLIC" and IP(address).version() == 4: self.publicipv4 = address # public IPv6 elif IP(address).iptype() == "ALLOCATED ARIN" and IP(address).version() == 6: self.publicipv6 = address # update the instance self.update() # ERROR status from openstack elif server.status == "ERROR": # instance failed to start, so delete and reset to paid response = instance_decommission(self) self.state = 2 # will be started again shortly self.update() response['response'] = "error" response['result']['message'] = "OpenStack errored on instance start." app.logger.error("OpenStack error on starting instance=(%s). Setting to restart." % self.name) # SPAWNING status from openstack else: # we all have limited time in this reality epoch_time = int(time.time()) # wait_timer is 5 minutes after the last update wait_timer = self.updated + 300 # test to see if we are 'hung' on SPAWNING for more than wait_timer if epoch_time > wait_timer: # we're now past when the instance needed to move to RUNNING response = instance_decommission(self) response['response'] = "error" response['result']['message'] = "Setting instance %s to restart." % self.name self.state = 2 # will be started shortly after this by start self.updated = epoch_time # given we 'timed' out, give the instance more time self.update() """ of anyplace, this is where you *might* want to add some time to the instance because a time based payment has been made on it. however, this could lead to a situation where an instance gets stuck in a circular state of erroring, getting more time, erroring again, rinse and repeat. instead of embracing this eventuality, we choose to short the customer her measly few cents instead, and let it serve as a as an excuse to add 'karma hits' on bad starts from providers as a feature later """ app.logger.error("OpenStack hung starting instance=(%s). Setting to restart." % self.name) else: # this is a 'soft' fail response['response'] = "error" response['result']['message'] = "Still starting instance=(%s)." % self.name # OpenStack reports instance NOT FOUND else: # we all have limited time in this reality epoch_time = int(time.time()) # we first check if we're outright expired (shouldn't happen) if self.expires < epoch_time: # no reason to be running as we're expired self.state = 7 # will be deleted shortly after this by trashman self.update() response['response'] = "error" response['result']['message'] = "Instance %s decommissioned." % self.name app.logger.error("OpenStack couldn't find expired instance=(%s). Decomissioning." % self.name) else: # we didn't find the instance in openstack, yet we should be running self.state = 2 # set to be started again self.update() response['response'] = "error" response['result']['message'] = "OpenStack couldn't find instance. Restarting." app.logger.error("OpenStack couldn't find instance=(%s). Setting to restart." % self.name) # make a call to the callback url to report instance details on state change if self.state != start_state: appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def start(self): from webapp.libs.openstack import flavor_verify_install from webapp.libs.openstack import image_verify_install from webapp.libs.openstack import instance_start # build the response response = {"response": "success", "result": {"message": ""}} # appliance appliance = Appliance().get() # load the callback url (expected to be None) callback_url = self.callback_url # check if instance needs to reset epoch_time = int(time.time()) if self.expires < epoch_time: # instance time expired, so don't start self.state = 1 self.update() response['response'] = "error" response['result']['message'] = "Instance payment is expired. Now waiting on payment." # we run a maximum of 7 callback checks for loop_count in range(7): # make a call to the callback url to get instance details next_state = 3 # hack the expected next state into the pool packet pool_response = pool_instance(url=callback_url, instance=self, next_state=next_state, appliance=appliance) # check for a failure to contact the callback server if pool_response['response'] == "error": self.message = pool_response['result']['message'] self.message_count = self.message_count + 1 self.update() return pool_response # look and see if we have a callback_url in the response try: callback_url = pool_response['result']['instance']['callback_url'] # run the loop again to call the callback url continue except: # break out break # for else returns a depth error else: response['response'] = "error" response['result']['message'] = "Callback depth exceeded." self.message = response['result']['message'] self.message_count = self.message_count + 1 self.update() return response # and lo, callback_url is saved self.callback_url = callback_url self.update() # get the image name if it exists in the response try: image_name = pool_response['result']['instance']['image'] image = db.session.query(Images).filter_by(name=image_name).first() self.image_id = image.id self.update() except: image_name = None # get the dynamic image url if it exists in the response try: dynamic_image_url = pool_response['result']['instance']['dynamic_image_url'] self.dynamic_image_url = dynamic_image_url self.update() except: # not good, but we can use a default image = db.session.query(Images).first() self.image_id = image.id self.update() # post creation file is blank to start post_creation_ssh_key_combo = "" # load the parser to unencode jinja2 template escaping from appliance h = HTMLParser() # ssh_key unrolling try: ssh_key = pool_response['result']['instance']['ssh_key'] # an array # loop through both strings and cat onto post_creation_ssh_key_combo # using prefered method of injecting keys with cloud-init post_creation_ssh_key_combo += "#cloud-config\n" post_creation_ssh_key_combo += "ssh_authorized_keys:\n" for line in ssh_key: post_creation_ssh_key_combo += " - %s\n" % h.unescape(line) post_creation_ssh_key_combo += "\n" except: # do nothing on various key failure pass # post creation configuration handling try: post_creation = pool_response['result']['instance']['post_creation'] # an array for line in post_creation: # import what the user put in the textbox for their wisp post_creation_ssh_key_combo += "%s\n" % h.unescape(line) except: # do nothing on post creation failure pass # update the instance with post creation self.post_creation = post_creation_ssh_key_combo self.update() # take the instance's flavor and verify install flavor = Flavors().get_by_id(self.flavor.id) osflavor = flavor_verify_install(flavor) if osflavor['response'] == "error": # we've failed to install flavor, so we disable it flavor.osid = "" flavor.active = 0 flavor.update() # now we disable the other instances using the flavor instances = Instances() instances.toggle(flavor.id, 0) # disable this instance self.state = 0 self.expires = self.created # zeros out the payment self.update() # log it app.logger.error("Disabling all instances using flavor=(%s) due to OpenStack failure." % flavor.name) # build the response and return response['response'] = "error" response['result']['message'] = "Error creating flavor inside OpenStack." return response # deal with creating dynamic image or use predefined one if self.dynamic_image_url: image = Images().get_or_create_by_instance(self) else: image = Images().get_by_id(self.image.id) if not image: response['response'] = "error" response['result']['message'] = "Error creating dynamic image." return response else: self.image = image self.update() # take the image and verify install osimage = image_verify_install(self.image) # handle failures of either flavor or image if osimage['response'] == "error": response['response'] = "error" response['result']['message'] = "Error creating image." return response # tell openstack to start the instance cluster_response = instance_start(self) # process response if cluster_response['response'] == "success": server = cluster_response['result']['server'] self.osid = server.id # assign openstack instance id self.state = 3 # mark as starting self.update() response['result'] = cluster_response['result'] else: response = cluster_response return response
def coinop(self, amount): # build response response = {"response": "success", "result": {"message": "", "instance": {}}} # calculate the purchased seconds based on payment we received ask = float(self.flavor.ask)/1000000 # BTC per hour try: purchased_seconds = (amount/ask)*3600 # amount in BTC/ask in BTC * seconds in hour except: purchased_seconds = 0 # handle local appliance start if amount == 0: purchased_seconds = 15*60 # give 15 minutes to instance for free # current UTC time in seconds since epoch epoch_time = int(time.time()) # if we're not running (state==1 or 10), set the run state to light (to be started) # if we're suspended (state==5), set the run state to relight (to be unsuspended) # cron jobs will take care of the rest of the job of starting/unsuspending # NOTE: We're getting paid pennies for doing nothing until cronjob runs! if self.state == 1 or self.state == 10: self.state = 2 self.expires = epoch_time + purchased_seconds # starting from now self.updated = epoch_time elif self.state == 5: self.state = 6 self.expires = epoch_time + purchased_seconds # starting from now self.updated = epoch_time else: # states 0, 2, 3, 4, 6, 7 self.expires = self.expires + purchased_seconds # starting from expire time self.updated = epoch_time # get instance console output - only run if we've got an osid # basically this only runs when we get a repayment if self.osid: from webapp.libs.openstack import instance_console response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] # update the instance self.update() # make a call to the callback url to report instance details callback_url = self.callback_url appliance = Appliance().get() pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) if pool_response['response'] == "success": # overload response response['result']['message'] = "Added %s seconds to %s's expire time." % (purchased_seconds, self.name) response['result']['instance'] = row2dict(self) else: # note the error in the instance object self.message_count = self.message_count + 1 self.message = pool_response['result']['message'] self.update() # load response and log response = pool_response app.logger.error("Error sending instance=(%s) data to pool." % self.name) return response
def housekeeping(self): from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_suspend from webapp.libs.openstack import instance_resume from webapp.libs.openstack import instance_decommission from webapp.libs.openstack import instance_console # build the response response = { "response": "success", "result": { "message": "", "server": {} } } # get instance (server) info cluster_response = instance_info(self) server = cluster_response['result']['server'] # we all have limited time in this reality epoch_time = int(time.time()) # set start state start_state = self.state # this is complicated...because we aren't EC with OpenStack...or I'm crazy if cluster_response['response'] == "success": # openstack responded it found this instance if server.status == "ACTIVE": # openstack says the server is running if self.expires < epoch_time: # suspend the instance for non-payment response = instance_suspend(self) response['result'][ 'message'] = "Instance %s suspended." % self.name self.state = 5 elif self.expires > epoch_time: # openstack says we're running, and we're paid if self.state == 5 or self.state == 6: # we move the instance to starting mode response['result'][ 'message'] = "Instance %s is starting." % self.name self.state = 3 elif server.status == "SUSPENDED": # openstack says this instance is suspended if self.expires > epoch_time: # should be running because not expired response = instance_resume(self) response['result'][ 'message'] = "Instance %s resumed." % self.name self.state = 3 # mark as starting if self.expires + app.config[ 'POOL_DECOMMISSION_TIME'] < epoch_time: # should be destroyed (suspended for +2 hours without pay) response['result'][ 'message'] = "Instance %s decommissioned." % self.name self.state = 7 else: # openstack indicates another state besides SUSPENDED or ACTIVE if self.expires > epoch_time: # we should be running, but in a weird state - destroy then restart response = instance_decommission(self) response['result'][ 'message'] = "Instance %s restarted." % self.name self.state = 2 # set as paid and ready to start app.logger.error( "OpenStack says instance=(%s) isn't in the correct state. Setting to restart." % self.name) else: # expired but in a weird state - destroy response = instance_decommission(self) response['result'][ 'message'] = "Instance %s decommissioned." % self.name self.state = 7 else: # openstack can't find this instance if self.expires > epoch_time: if self.state == 2: # check error rate if self.message_count > 10: # we're failing to start the instance, so decomission response['result'][ 'message'] = "Instance %s decommissioned." % self.name self.state = 7 app.logger.error( "Exceeded error rate on callbacks for instance=(%s). Decomissioning." % self.name) else: # set instance to restart - not expired, should be running response[ 'response'] = "error" # technically, someone is probably f*****g with things response['result'][ 'message'] = "Setting instance %s to restart." % self.name self.state = 2 # will be started shortly after this by start app.logger.error( "OpenStack doesn't know about instance=(%s). Setting to restart." % self.name) else: # no reason to be running response['response'] = "error" response['result'][ 'message'] = "Instance %s decommissioned." % self.name self.state = 7 # will be deleted shortly after this by trashman # get instance console output cluster_response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] # update self.update() # make a call to the callback url to report instance details on state change if self.state != start_state: appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def nudge(self): from webapp.libs.openstack import try_associate_floating_ip from webapp.libs.openstack import instance_info from webapp.libs.openstack import instance_console from webapp.libs.openstack import instance_decommission # get instance console output response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] self.update() # get instance (server) info response = instance_info(self) # set start state start_state = self.state # set instance meta data if response['response'] == "success": server = response['result']['server'] # if the state is ACTIVE, we set to be running state==4 if server.status == "ACTIVE": # set network info self.state = 4 # try to get a floating ip for the new server float_response = try_associate_floating_ip(server) # check if call got a floating IP if float_response['response'] == "success": # get instance info again to pick up new IP response = instance_info(self) # load the response into the server object if response['response'] == "success": server = response['result']['server'] else: # log 'errors' in floating assignment app.logger.info(float_response['result']['message']) # extract IP addresses using IPy # in some circumstances this will squash multiple same/same address types # we only extract and store one each of private ipv4, public ipv4, and public ipv6 for key in server.networks.keys(): # any network names for address in server.networks[ key]: # loop through each address for each network # private IPv4 if IP(address).iptype() == "PRIVATE" and IP( address).version() == 4: self.privateipv4 = address # public IPv4 elif IP(address).iptype() == "PUBLIC" and IP( address).version() == 4: self.publicipv4 = address # public IPv6 elif IP(address).iptype() == "ALLOCATED ARIN" and IP( address).version() == 6: self.publicipv6 = address # update the instance self.update() # ERROR status from openstack elif server.status == "ERROR": # instance failed to start, so delete and reset to paid response = instance_decommission(self) self.state = 2 # will be started again shortly self.update() response['response'] = "error" response['result'][ 'message'] = "OpenStack errored on instance start." app.logger.error( "OpenStack error on starting instance=(%s). Setting to restart." % self.name) # SPAWNING status from openstack else: # we all have limited time in this reality epoch_time = int(time.time()) # wait_timer is 5 minutes after the last update wait_timer = self.updated + 300 # test to see if we are 'hung' on SPAWNING for more than wait_timer if epoch_time > wait_timer: # we're now past when the instance needed to move to RUNNING response = instance_decommission(self) response['response'] = "error" response['result'][ 'message'] = "Setting instance %s to restart." % self.name self.state = 2 # will be started shortly after this by start self.updated = epoch_time # given we 'timed' out, give the instance more time self.update() """ of anyplace, this is where you *might* want to add some time to the instance because a time based payment has been made on it. however, this could lead to a situation where an instance gets stuck in a circular state of erroring, getting more time, erroring again, rinse and repeat. instead of embracing this eventuality, we choose to short the customer her measly few cents instead, and let it serve as a as an excuse to add 'karma hits' on bad starts from providers as a feature later """ app.logger.error( "OpenStack hung starting instance=(%s). Setting to restart." % self.name) else: # this is a 'soft' fail response['response'] = "error" response['result'][ 'message'] = "Still starting instance=(%s)." % self.name # OpenStack reports instance NOT FOUND else: # we all have limited time in this reality epoch_time = int(time.time()) # we first check if we're outright expired (shouldn't happen) if self.expires < epoch_time: # no reason to be running as we're expired self.state = 7 # will be deleted shortly after this by trashman self.update() response['response'] = "error" response['result'][ 'message'] = "Instance %s decommissioned." % self.name app.logger.error( "OpenStack couldn't find expired instance=(%s). Decomissioning." % self.name) else: # we didn't find the instance in openstack, yet we should be running self.state = 2 # set to be started again self.update() response['response'] = "error" response['result'][ 'message'] = "OpenStack couldn't find instance. Restarting." app.logger.error( "OpenStack couldn't find instance=(%s). Setting to restart." % self.name) # make a call to the callback url to report instance details on state change if self.state != start_state: appliance = Appliance().get() callback_url = self.callback_url pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) return response
def start(self): from webapp.libs.openstack import flavor_verify_install from webapp.libs.openstack import image_verify_install from webapp.libs.openstack import instance_start # build the response response = {"response": "success", "result": {"message": ""}} # appliance appliance = Appliance().get() # load the callback url (expected to be None) callback_url = self.callback_url # check if instance needs to reset epoch_time = int(time.time()) if self.expires < epoch_time: # instance time expired, so don't start self.state = 1 self.update() response['response'] = "error" response['result'][ 'message'] = "Instance payment is expired. Now waiting on payment." # we run a maximum of 7 callback checks for loop_count in range(7): # make a call to the callback url to get instance details next_state = 3 # hack the expected next state into the pool packet pool_response = pool_instance(url=callback_url, instance=self, next_state=next_state, appliance=appliance) # check for a failure to contact the callback server if pool_response['response'] == "error": self.message = pool_response['result']['message'] self.message_count = self.message_count + 1 self.update() return pool_response # look and see if we have a callback_url in the response try: callback_url = pool_response['result']['instance'][ 'callback_url'] # run the loop again to call the callback url continue except: # break out break # for else returns a depth error else: response['response'] = "error" response['result']['message'] = "Callback depth exceeded." self.message = response['result']['message'] self.message_count = self.message_count + 1 self.update() return response # and lo, callback_url is saved self.callback_url = callback_url self.update() # get the image name if it exists in the response try: image_name = pool_response['result']['instance']['image'] image = db.session.query(Images).filter_by(name=image_name).first() self.image_id = image.id self.update() except: image_name = None # get the dynamic image url if it exists in the response try: dynamic_image_url = pool_response['result']['instance'][ 'dynamic_image_url'] self.dynamic_image_url = dynamic_image_url self.update() except: # not good, but we can use a default image = db.session.query(Images).first() self.image_id = image.id self.update() # post creation file is blank to start post_creation_ssh_key_combo = "" # load the parser to unencode jinja2 template escaping from appliance h = HTMLParser() # ssh_key unrolling try: ssh_key = pool_response['result']['instance'][ 'ssh_key'] # an array # loop through both strings and cat onto post_creation_ssh_key_combo # using prefered method of injecting keys with cloud-init post_creation_ssh_key_combo += "#cloud-config\n" post_creation_ssh_key_combo += "ssh_authorized_keys:\n" for line in ssh_key: post_creation_ssh_key_combo += " - %s\n" % h.unescape(line) post_creation_ssh_key_combo += "\n" except: # do nothing on various key failure pass # post creation configuration handling try: post_creation = pool_response['result']['instance'][ 'post_creation'] # an array for line in post_creation: # import what the user put in the textbox for their wisp post_creation_ssh_key_combo += "%s\n" % h.unescape(line) except: # do nothing on post creation failure pass # update the instance with post creation self.post_creation = post_creation_ssh_key_combo self.update() # take the instance's flavor and verify install flavor = Flavors().get_by_id(self.flavor.id) osflavor = flavor_verify_install(flavor) if osflavor['response'] == "error": # we've failed to install flavor, so we disable it flavor.osid = "" flavor.active = 0 flavor.update() # now we disable the other instances using the flavor instances = Instances() instances.toggle(flavor.id, 0) # disable this instance self.state = 0 self.expires = self.created # zeros out the payment self.update() # log it app.logger.error( "Disabling all instances using flavor=(%s) due to OpenStack failure." % flavor.name) # build the response and return response['response'] = "error" response['result'][ 'message'] = "Error creating flavor inside OpenStack." return response # deal with creating dynamic image or use predefined one if self.dynamic_image_url: image = Images().get_or_create_by_instance(self) else: image = Images().get_by_id(self.image.id) if not image: response['response'] = "error" response['result']['message'] = "Error creating dynamic image." return response else: self.image = image self.update() # take the image and verify install osimage = image_verify_install(self.image) # handle failures of either flavor or image if osimage['response'] == "error": response['response'] = "error" response['result']['message'] = "Error creating image." return response # tell openstack to start the instance cluster_response = instance_start(self) # process response if cluster_response['response'] == "success": server = cluster_response['result']['server'] self.osid = server.id # assign openstack instance id self.state = 3 # mark as starting self.update() response['result'] = cluster_response['result'] else: response = cluster_response return response
def coinop(self, amount): # build response response = { "response": "success", "result": { "message": "", "instance": {} } } # calculate the purchased seconds based on payment we received ask = float(self.flavor.ask) / 1000000 # BTC per hour try: purchased_seconds = ( amount / ask) * 3600 # amount in BTC/ask in BTC * seconds in hour except: purchased_seconds = 0 # handle local appliance start if amount == 0: purchased_seconds = 15 * 60 # give 15 minutes to instance for free # current UTC time in seconds since epoch epoch_time = int(time.time()) # if we're not running (state==1 or 10), set the run state to light (to be started) # if we're suspended (state==5), set the run state to relight (to be unsuspended) # cron jobs will take care of the rest of the job of starting/unsuspending # NOTE: We're getting paid pennies for doing nothing until cronjob runs! if self.state == 1 or self.state == 10: self.state = 2 self.expires = epoch_time + purchased_seconds # starting from now self.updated = epoch_time elif self.state == 5: self.state = 6 self.expires = epoch_time + purchased_seconds # starting from now self.updated = epoch_time else: # states 0, 2, 3, 4, 6, 7 self.expires = self.expires + purchased_seconds # starting from expire time self.updated = epoch_time # get instance console output - only run if we've got an osid # basically this only runs when we get a repayment if self.osid: from webapp.libs.openstack import instance_console response = instance_console(self) if 'console' in response['result']: self.console = response['result']['console'] # update the instance self.update() # make a call to the callback url to report instance details callback_url = self.callback_url appliance = Appliance().get() pool_response = pool_instance(url=callback_url, instance=self, appliance=appliance) if pool_response['response'] == "success": # overload response response['result'][ 'message'] = "Added %s seconds to %s's expire time." % ( purchased_seconds, self.name) response['result']['instance'] = row2dict(self) else: # note the error in the instance object self.message_count = self.message_count + 1 self.message = pool_response['result']['message'] self.update() # load response and log response = pool_response app.logger.error("Error sending instance=(%s) data to pool." % self.name) return response