def configure_instances(): # check configuration settings = Status().check_settings() # load instances ordering by state instances = db.session.query(Instances).order_by("state desc").all() # images images = Images() images = images.get_all() return render_template("configure/instances.html", settings=settings, instances=instances, images=images)
def configure_instances(): # check configuration settings = Status().check_settings() # load instances ordering by state instances = db.session.query(Instances).order_by("state desc").all() # images images = Images() images = images.get_all() return render_template('configure/instances.html', settings=settings, instances=instances, images=images)
def action(): """ Cleans up images that aren't used anymore Cron: Every 15 minutes. """ # clear out old dynamic images images = Images.get_all() for image in images: image.housekeeping()
def action(): """ Performs a sync from the pool's list of images to the appliance. Cron: Every 15 minutes. """ # get the appliance for api token (not required, but sent if we have it) appliance = db.session.query(Appliance).first() # sync up all the images images = Images() response = images.sync(appliance) # now loop through and download non dynamic images if we don't have the files images = db.session.query(Images).filter_by(cache=1).all() download_images(appliance, images) # clear out old dynamic images images = db.session.query(Images).filter_by(cache=0).all() for image in images: image.housekeeping()
def action(ip=('i', default_ip)): """ Restores the appliance to factory default settings. """ try: if ip == default_ip: print "Please enter the appliance's IP address." print "Usage: ./manage.py reset -i x.x.x.x" return action # double check they want to do this if query_yes_no("Are you sure you want to reset the appliance?"): # initialize database path = os.path.dirname(os.path.abspath(__file__)) os.system('sqlite3 "%s/utterio.db" < "%s/schema.sql"' % (path, path)) # initialize the appliance object appliance = Appliance() appliance.initialize(ip) # sync with pool database images = Images() iresponse = images.sync(appliance) flavors = Flavors() fresponse = flavors.sync(appliance) if iresponse['response'] != "success": print iresponse['result'] elif fresponse['response'] != "success": print iresponse['result'] else: print "The database has been cleared and a new API token has been generated." configure_blurb() except ValueError as ex: print ex
def action(ip=('i', default_ip)): """ Installs a new database configuration for the appliance. """ # run database reset script - use current path to run file path = os.path.dirname(os.path.abspath(__file__)) # initialize database os.system('sqlite3 "%s/utterio.db" < "%s/schema.sql"' % (path, path)) # initialize the appliance object appliance = Appliance() appliance.initialize(ip) # sync to remote database images = Images() response = images.sync(appliance) flavors = Flavors() response = flavors.sync(appliance) # configure output configure_blurb()
def start(self): from webapp.libs.openstack import flavor_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 first time through) 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): # set state to 3 just for the pool self.state = 3 # make a call to the callback url to get instance details pool_response = pool_instances( url=callback_url, instance=self, appliance=appliance) # and set it back to 2 because we don't know yet if it's actually starting self.state = 2 # 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: # run the loop again to call the callback url if pool_response['result']['instance']['callback_url'] == '': break else: callback_url = pool_response['result']['instance']['callback_url'] except: # catch no callback_url keys break 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 # get dictionary from pool's reply start_params = schemas['InstanceStartParametersSchema']( **pool_response['result']['instance']).as_dict() # and lo, callback_url is saved self.callback_url = callback_url # lookup the image for this instance, or create it otherwise image = self.image if not image: image = Images.query.filter_by( **dict( filter( lambda x: x[0] in ['url', 'container_format', 'disk_format'], start_params['image'].items()))).first() self.update(image=image) if image and not image.osid: image.delete() image = None if not image: image = Images(**start_params['image']) self.update(image=image) try: image.save() except Exception as e: app.logger.warning("Error creating image using copy_from, attempt proxying: \"{0}\"".format(str(e))) response = self._proxy_image(image) if response['response'] != 'success': return response # if image is not ready because it's either killed or still downloading try: image_status = image.status except Exception as e: err_string = "Error communicating with OpenStack: \"{0}\"".format(str(e)) app.logger.error(err_string) response['response'] = "error" response['result']['message'] = err_string return response if image_status == "queued" or image_status == "saving": # image is still downloading and is not ready to be used yet response['response'] = "queued" response['result']['message'] = "image is being created" return response elif image_status == "killed": # image has been killed, prossibly our openstack is a nebula response = self._proxy_image(image) if response['response'] != 'success': return response # post creation file is blank to start post_creation_combo = "" # load the parser to unencode jinja2 template escaping from appliance h = HTMLParser() # ssh_key unrolling try: # loop through both strings and cat onto post_creation_ssh_key_combo # using prefered method of injecting keys with cloud-init post_creation_combo += "#cloud-config\n" post_creation_combo += "ssh_authorized_keys:\n" for line in start_params['ssh_keys']: post_creation_combo += " - %s\n" % h.unescape(line) post_creation_combo += "\n" except: # do nothing on various key failure pass # create utterio file data post_creation_file_data = "" post_creation_file_data += "export MY_BITCOIN_ADDRESS=%s\n" % self.address post_creation_file_data += "export MY_POOL_API_ADDRESS=%s/api/v1/instances/%s/\n" % (app.config['APP_WEBSITE'], self.name) # payment address source file post_creation_combo += "write_files:\n" post_creation_combo += "- encoding: b64\n" post_creation_combo += ' content: %s\n' % base64.b64encode(post_creation_file_data) post_creation_combo += " path: /etc/utterio\n" post_creation_combo += " permissions: '0644'\n" # post creation configuration handling try: for line in start_params['post_create']: # import what the user put in the textbox for their wisp post_creation_combo += "%s\n" % h.unescape(line) post_creation_combo += "\n" except: # do nothing on post creation failure pass # update the instance with post creation self.post_creation = post_creation_combo self.update() # take the instance's flavor and verify install flavor = models.flavors.Flavors().get_by_id(self.flavor.id) flavor_response = flavor_verify_install(flavor) if flavor_response['response'] == "error" or flavor_response['response'] == "forbidden": # 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() if flavor_response['response'] == "forbidden": response['result']['message'] = \ "Not allowed to create flavor inside OpenStack." # log it app.logger.error("Disabling all instances using flavor=(%s) and disabling " "creation of flavors due to lack of permissions." % flavor.name) else: # log it app.logger.error("Disabling all instances using flavor=(%s) due to " "OpenStack failure." % flavor.name) # build the response and return response['result']['message'] = flavor_response['result']['message'] response['response'] = "error" 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.update(osid=server.id, state=3) response['result'] = cluster_response['result'] else: response = cluster_response return response
def start(self): from webapp.libs.openstack import flavor_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 first time through) 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): # set state to 3 just for the pool self.state = 3 # make a call to the callback url to get instance details pool_response = pool_instances(url=callback_url, instance=self, appliance=appliance) # and set it back to 2 because we don't know yet if it's actually starting self.state = 2 # 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: # run the loop again to call the callback url if pool_response['result']['instance']['callback_url'] == '': break else: callback_url = pool_response['result']['instance'][ 'callback_url'] except: # catch no callback_url keys break 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 # get dictionary from pool's reply start_params = schemas['InstanceStartParametersSchema']( **pool_response['result']['instance']).as_dict() # and lo, callback_url is saved self.callback_url = callback_url # lookup the image for this instance, or create it otherwise image = self.image if not image: image = Images.query.filter_by(**dict( filter( lambda x: x[ 0] in ['url', 'container_format', 'disk_format'], start_params['image'].items()))).first() self.update(image=image) if image and not image.osid: image.delete() image = None if not image: image = Images(**start_params['image']) self.update(image=image) try: image.save() except Exception as e: app.logger.warning( "Error creating image using copy_from, attempt proxying: \"{0}\"" .format(str(e))) response = self._proxy_image(image) if response['response'] != 'success': return response # if image is not ready because it's either killed or still downloading try: image_status = image.status except Exception as e: err_string = "Error communicating with OpenStack: \"{0}\"".format( str(e)) app.logger.error(err_string) response['response'] = "error" response['result']['message'] = err_string return response if image_status == "queued" or image_status == "saving": # image is still downloading and is not ready to be used yet response['response'] = "queued" response['result']['message'] = "image is being created" return response elif image_status == "killed": # image has been killed, prossibly our openstack is a nebula response = self._proxy_image(image) if response['response'] != 'success': return response # post creation file is blank to start post_creation_combo = "" # load the parser to unencode jinja2 template escaping from appliance h = HTMLParser() # ssh_key unrolling try: # loop through both strings and cat onto post_creation_ssh_key_combo # using prefered method of injecting keys with cloud-init post_creation_combo += "#cloud-config\n" post_creation_combo += "ssh_authorized_keys:\n" for line in start_params['ssh_keys']: post_creation_combo += " - %s\n" % h.unescape(line) post_creation_combo += "\n" except: # do nothing on various key failure pass # create utterio file data post_creation_file_data = "" post_creation_file_data += "export MY_BITCOIN_ADDRESS=%s\n" % self.address post_creation_file_data += "export MY_POOL_API_ADDRESS=%s/api/v1/instances/%s/\n" % ( app.config['APP_WEBSITE'], self.name) # payment address source file post_creation_combo += "write_files:\n" post_creation_combo += "- encoding: b64\n" post_creation_combo += ' content: %s\n' % base64.b64encode( post_creation_file_data) post_creation_combo += " path: /etc/utterio\n" post_creation_combo += " permissions: '0644'\n" # post creation configuration handling try: for line in start_params['post_create']: # import what the user put in the textbox for their wisp post_creation_combo += "%s\n" % h.unescape(line) post_creation_combo += "\n" except: # do nothing on post creation failure pass # update the instance with post creation self.post_creation = post_creation_combo self.update() # take the instance's flavor and verify install flavor = models.flavors.Flavors().get_by_id(self.flavor.id) flavor_response = flavor_verify_install(flavor) if flavor_response['response'] == "error" or flavor_response[ 'response'] == "forbidden": # 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() if flavor_response['response'] == "forbidden": response['result']['message'] = \ "Not allowed to create flavor inside OpenStack." # log it app.logger.error( "Disabling all instances using flavor=(%s) and disabling " "creation of flavors due to lack of permissions." % flavor.name) else: # log it app.logger.error( "Disabling all instances using flavor=(%s) due to " "OpenStack failure." % flavor.name) # build the response and return response['result']['message'] = flavor_response['result'][ 'message'] response['response'] = "error" 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.update(osid=server.id, state=3) response['result'] = cluster_response['result'] else: response = cluster_response 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