Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
    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()
Ejemplo n.º 4
0
	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()
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
	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()		
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
	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
Ejemplo n.º 9
0
    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()
Ejemplo n.º 10
0
	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()
Ejemplo n.º 11
0
	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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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