Esempio n. 1
0
    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_instances(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
Esempio n. 2
0
	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_instances(
				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
Esempio n. 3
0
	def sync(self, appliance):
		# grab addresses from coinbase
		response = coinbase_get_addresses(appliance=appliance)

		if response['response'] == "success":
			remoteaddresses = response['result']['addresses']

			# update database with remote addresses
			for remoteaddress_address in remoteaddresses:
				# work around coinbase's strange address:address thing
				remoteaddress = remoteaddress_address['address']

				# check if address label is the md5 of our coinbase api key
				if remoteaddress['label'] == md5.new(appliance.cbapikey).hexdigest():

					# see if we have a matching address
					address = db.session.query(Addresses).filter_by(address=remoteaddress['address']).first()
					
					# we don't have the address at coinbase in database
					if address is None:
						# create a new address
						address = Addresses()
						address.address = remoteaddress['address']
						address.token = urlparse(remoteaddress['callback_url']).path.split('/')[-1]
						address.instance_id = 0 # no instances yet
						address.subdomain = urlparse(remoteaddress['callback_url']).hostname.split('.')[0]

						# add and commit
						address.update(address)

					# we have the address already and need to update it
					else:
						# update address from remote addresses
						address.address = remoteaddress['address']
						address.token = urlparse(remoteaddress['callback_url']).path.split('/')[-1]
						address.subdomain = urlparse(remoteaddress['callback_url']).hostname.split('.')[0]

						# add and commit
						address.update(address)

				else:
					# must be another appliance's address so skip it
					pass

			# overload the results with the list of current addresses
			response['result']['addresses'] = []
			addresses = db.session.query(Addresses).all()

			for address in addresses:
				response['result']['addresses'].append(row2dict(address))

			return response

		# failure contacting server
		else:
			app.logger.error("Error contacting Coinbase during sync.")
			# lift respose from server call to view
			return response
Esempio n. 4
0
def flavor_error_response(message, flavor=None):
	# response
	response['response'] = "error"
	response['result']['flavor'] = row2dict(flavor)
	response['result']['message'] = "%s" % message
	
	# disable flavor	
	flavor.osid = ""
	flavor.active = 0
	flavor.update()

	# log it
	app.logger.error("Failed to install flavor=(%s) into the OpenStack cluster. %s" % (flavor.name, message))

	return response
Esempio n. 5
0
def configure_flavors_detail(flavor_id):
    # get the matching flavor
    flavor = db.session.query(Flavors).filter_by(id=flavor_id).first()

    # handle a GET
    if request.method == 'GET':
        # check configuration
        settings = Status().check_settings()

        # how much is a micro BTC?
        try:
            quote = float(
                coinbase_get_quote(
                    currency='btc_to_usd')['result']['btc_to_usd']) / 1000000
        except:
            quote = 0

        return render_template('/configure/flavor_detail.html',
                               settings=settings,
                               quote=quote,
                               flavor=flavor)

    # handle a PUT
    elif request.method == 'PUT':
        # clear settings cache
        Status().flush()

        try:
            state = int(request.form['enable'])
            flavor.active = state

            # set instances with this flavor to the state
            instances = Instances()
            instances.toggle(flavor.id, state)

        except:
            pass

        try:
            ask = request.form['ask']
            flavor.ask = ask
        except:
            pass

        # update entry
        flavor.update()

        return jsonify({"response": "success", "flavor": row2dict(flavor)})
Esempio n. 6
0
def flavor_error_response(message, flavor=None):
    # response
    response['response'] = "error"
    response['result']['flavor'] = row2dict(flavor)
    response['result']['message'] = "%s" % message

    # disable flavor
    flavor.osid = ""
    flavor.active = 0
    flavor.update()

    # log it
    app.logger.error(
        "Failed to install flavor=(%s) into the OpenStack cluster. %s" %
        (flavor.name, message))

    return response
Esempio n. 7
0
def configure_flavors_detail(flavor_id):
    # get the matching flavor
    flavor = db.session.query(Flavors).filter_by(id=flavor_id).first()

    # handle a GET
    if request.method == "GET":
        # check configuration
        settings = Status().check_settings()

        # how much is a micro BTC?
        try:
            quote = float(coinbase_get_quote(currency="btc_to_usd")["result"]["btc_to_usd"]) / 1000000
        except:
            quote = 0

        return render_template("/configure/flavor_detail.html", settings=settings, quote=quote, flavor=flavor)

        # handle a PUT
    elif request.method == "PUT":
        # clear settings cache
        Status().flush()

        try:
            state = int(request.form["enable"])
            flavor.active = state

            # set instances with this flavor to the state
            instances = Instances()
            instances.toggle(flavor.id, state)

        except:
            pass

        try:
            ask = request.form["ask"]
            flavor.ask = ask
        except:
            pass

            # update entry
        flavor.update()

        return jsonify({"response": "success", "flavor": row2dict(flavor)})
Esempio n. 8
0
	def sync(self, appliance):
		# grab image list from pool server
		response = pool_connect(method="images", appliance=appliance)

		if response['response'] == "success":
			remoteimages = response['result']
					
			# update database for images
			for remoteimage in remoteimages['images']:
				# see if we have a matching image
				image = db.session.query(Images).filter_by(name=remoteimage['name']).first()
				
				# check if we need to delete image from local db
				# b'001000' indicates delete image
				# TODO: need to cleanup OpenStack images if we uninstall
				if (remoteimage['flags'] & 8) == 8:
					# only delete if we have it
					if image is not None:
						# try to delete the local copy
						uninstall_image(image)

						# remove the image from the database
						image.delete(image)
					else:
						# we don't have it, so we do nothing
						pass

				# we don't have the image coming in from the server, so install
				elif image is None:
					# create a new image
					image = Images()
					epoch_time = int(time.time())
					image.created = epoch_time
					image.updated = epoch_time
					image.name = remoteimage['name']
					image.description = remoteimage['description']
					image.url = remoteimage['url']
					image.size = remoteimage['size'] # used as a suggestion of size only
					image.cache = 1 # cache locally (unlike dynamic images)
					image.diskformat = remoteimage['diskformat']
					image.containerformat = remoteimage['containerformat']
					image.active = 1 # indicates we know about it, but not downloaded
					image.flags = remoteimage['flags']

					# add and commit
					image.update(image)

				else:
					# update image from remote images (local lookup was by name)
					epoch_time = int(time.time())
					image.description = remoteimage['description']
					if image.url != remoteimage['url']:
						image.url = remoteimage['url']
						image.updated = epoch_time
					if image.diskformat != remoteimage['diskformat']:
						image.diskformat = remoteimage['diskformat']
						image.updated = epoch_time
					if image.containerformat != remoteimage['containerformat']:
						image.containerformat = remoteimage['containerformat']
						image.updated = epoch_time
					if image.flags != remoteimage['flags']:
						image.flags = remoteimage['flags']
						image.updated = epoch_time

					# update
					image.update(image)

			# grab a new copy of the images in database
			images = db.session.query(Images).all()

			# overload the results with the list of current images
			response['result']['images'] = []
			images = db.session.query(Images).all()

			for image in images:
				response['result']['images'].append(row2dict(image))

			return response

		# failure contacting server
		else:
			# lift respose from server call to view
			return response
Esempio n. 9
0
	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_instances(
			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
Esempio n. 10
0
def pool_salesman(instances=None, appliance=None):
    from webapp.libs.openstack import get_stats

    # form the URL to advertise instance for sale
    url = "%s/api/v1/broker/" % (app.config['POOL_APPSPOT_WEBSITE'])

    # grab the cluster's stats
    try:
        response = get_stats()
        stats = response['result']['stats']
    except:
        stats = {}

    # build the sales packet
    packet = {
        "appliance": {
            "apitoken": appliance.apitoken,
            "dynamicimages": appliance.dynamicimages,
            "location": {
                "latitude": appliance.latitude,
                "longitude": appliance.longitude
            },
            "stats": stats
        },
        "instances": []
    }

    # response
    response = {"response": "success", "result": {"message": ""}}

    # loop through advertised instances
    for instance in instances:
        try:
            # convert to a dict
            pool_instance = row2dict(instance)

            # patch in flavor, ask, default image, address
            pool_instance['flavor'] = {
                "vpus": instance.flavor.vpus,
                "memory": instance.flavor.memory,
                "disk": instance.flavor.disk,
                "network_up": instance.flavor.network_up,
                "network_down": instance.flavor.network_down,
                "ask": instance.flavor.ask
            }
            pool_instance['state'] = instance.state
            pool_instance['address'] = instance.address

            # add instances to the data packet
            packet['instances'].append(pool_instance)

        except:
            # something didn't go right somewhere, so just nail the instance
            app.logger.error("Instance=(%s) integrity error." % instance.name)
            # instance.delete(instance)

    try:
        request = Request(url)
        request.add_header('Content-Type', 'application/json')
        response = json.loads(
            urlopen(request, json.dumps(packet), timeout=10).read())
        app.logger.info(
            "Appliance has placed quantity=(%s) instances up for sale." %
            len(instances))

    except HTTPError as ex:
        response['response'] = "error"
        response['result'][
            'message'] = "Error code %s returned from server." % ex.code
    except IOError as ex:
        response['response'] = "error"
        response['result'][
            'message'] = "Can't contact callback server.  Try again later."
    except ValueError as ex:
        response['response'] = "error"
        response['result'][
            'message'] = "Having issues parsing JSON from the site: %s.  Open a ticket." % type(
                ex).__name__
    except Exception as ex:
        response['response'] = "error"
        response['result'][
            'message'] = "An error of type %s has occured.  Open a ticket." % type(
                ex).__name__

    return response
Esempio n. 11
0
def configure_flavors_detail(flavor_id):
    # get the matching flavor
    flavor = db.session.query(Flavors).filter_by(id=flavor_id).first()

    # clear settings cache
    Status().flush()

    # enable/diskable
    if 'enable' in request.form.keys():
        flavor.update(active=int(request.form['enable']))

    # set ask
    if 'ask' in request.form.keys():
        flavor.update(ask=int(request.form['ask']))

    # set max-instances
    if 'max-instances' in request.form.keys():
        flavor.update(max_instances=int(request.form['max-instances']))

    # install pool flavor
    if 'install' in request.form.keys():
        # let's see what we can break, er install
        try:
            if not flavor:
                response = jsonify({
                    "response": "error",
                    "result": {
                        "message": "Flavor %s not found." % flavor_id
                    }
                })
                response.status_code = 404
                return response

            # we are told to install
            if int(request.form['install']):
                response = flavor_verify_install(flavor)
                if not response['response'] == 'success':
                    raise Exception(response['result']['message'])

                if flavor.ask > 0:
                    flavor.update(active=True)
                else:
                    flavor.update(active=False)
            else:
                # we are told to uninstall (install=0)
                response = flavor_uninstall(flavor)
                if not response['response'] == 'success':
                    raise Exception(response['result']['message'])

                flavor.update(installed=False, active=False, osid=None)

        except Exception as e:
            response = jsonify({
                "response": "error",
                "result": {
                    "message": str(e)
                }
            })
            response.status_code = 403
            return response

    # set instance state to match flavor's state
    instances = Instances()
    instances.toggle(flavor.id, flavor.active)

    # update the ask prices on the openstack cluster using metadata
    try:
        # get current ask price on openstack and update
        flavor.save()

    # warn because we couldn't update the ask price that's set on openstack
    except nova_exceptions.Forbidden:
        app.logger.warning(
            'No permissions to update price of flavor "{0}".'.format(
                flavor.name))
        return response

    # handle any other exception while talking to openstack
    except Exception as e:
        app.logger.warning('Error updating price of flavor "{0}": {1}.'.format(
            flavor.name, str(e)))

    return jsonify({"response": "success", "flavor": row2dict(flavor)})
Esempio n. 12
0
def pool_salesman(instances=None, appliance=None):
	from webapp.libs.openstack import get_stats

	# form the URL to advertise instance for sale
	url = "%s/api/v1/broker/" % (
		app.config['POOL_APPSPOT_WEBSITE']
	)

	# grab the cluster's stats
	try:
		response = get_stats()
		stats = response['result']['stats']
	except:
		stats = {}

	# build the sales packet
	packet = { 
		"appliance": {
			"apitoken": appliance.apitoken, 
			"dynamicimages": appliance.dynamicimages,
			"location": {
				"latitude": appliance.latitude,
				"longitude": appliance.longitude
			},
			"stats": stats
		},
		"instances": []
	}

	# response
	response = {"response": "success", "result": {"message": ""}}

	# loop through advertised instances
	for instance in instances:
		try:
			# convert to a dict
			pool_instance = row2dict(instance)

			# patch in flavor, ask, default image, address
			pool_instance['flavor'] = instance.flavor.name
			pool_instance['ask'] = instance.flavor.ask
			pool_instance['state'] = instance.state
			pool_instance['image'] = instance.image.name
			pool_instance['address'] = instance.address.address

			# add instances to the data packet
			packet['instances'].append(pool_instance)
		
		except:
			# something didn't go right somewhere, so just nail the instance
			app.logger.error("Instance=(%s) integrity error." % instance.name)
			instance.delete(instance)

	try:
		request = Request(url)
		request.add_header('Content-Type', 'application/json')
		response = json.loads(urlopen(request, json.dumps(packet), timeout=10).read())
		app.logger.info("Appliance has placed quantity=(%s) instances up for sale." % len(instances))

	except HTTPError as ex:
		response['response'] = "error"
		response['result']['message'] = "Error code %s returned from server." % ex.code
	except IOError as ex:
		response['response'] = "error"
		response['result']['message'] = "Can't contact callback server.  Try again later."
	except ValueError as ex:
		response['response'] = "error"
		response['result']['message'] = "Having issues parsing JSON from the site: %s.  Open a ticket." % type(ex).__name__
	except Exception as ex:
		response['response'] = "error"
		response['result']['message'] = "An error of type %s has occured.  Open a ticket." % type(ex).__name__

	return response
Esempio n. 13
0
	def sync(self, appliance):
		# grab image list from pool server
		response = pool_connect(method="flavors", appliance=appliance)

		# remote sync
		if response['response'] == "success":
			remoteflavors = response['result']

			# update the database with the flavors
			for remoteflavor in remoteflavors['flavors']:
				flavor = db.session.query(Flavors).filter_by(name=remoteflavor['name']).first()

				# check if we need to delete flavor from local db
				# b'001000' indicates delete image
				# TODO: need to cleanup OpenStack flavor if we uninstall
				if (remoteflavor['flags'] & 8) == 8:
					# only delete if we have it
					if flavor is not None:
						# remove the flavor from the database
						flavor.delete(flavor)
					else:
						# we don't have it, so we do nothing
						pass

				elif flavor is None:
					# we don't have the flavor coming in from the server
					flavor = Flavors()

					# create a new flavor
					flavor.name = remoteflavor['name']
					flavor.description = remoteflavor['description']
					flavor.vpus = remoteflavor['vpus']
					flavor.memory = remoteflavor['memory']
					flavor.disk = remoteflavor['disk']
					flavor.network = remoteflavor['network']
					flavor.rate = remoteflavor['rate']
					flavor.ask = remoteflavor['rate'] # set ask to market rate
					flavor.hot = remoteflavor['hot']
					flavor.launches = remoteflavor['launches']
					flavor.flags = remoteflavor['flags']
					flavor.active = 1

					# add and commit
					flavor.update(flavor)

				# we have the flavor and need to update it	
				else:
					# we have the flavor already, so update
					flavor.name = remoteflavor['name']
					flavor.description = remoteflavor['description']
					flavor.vpus = remoteflavor['vpus']
					flavor.memory = remoteflavor['memory']
					flavor.disk = remoteflavor['disk']
					flavor.network = remoteflavor['network']
					flavor.rate = remoteflavor['rate']
					flavor.hot = remoteflavor['hot']
					# we leave flavor.ask alone
					# we leave flavor.active alone
					flavor.launches = remoteflavor['launches']
					flavor.flags = remoteflavor['flags']
					
					# update
					flavor.update(flavor)

			# overload the results with the list of current flavors
			response['result']['flavors'] = []
			flavors = db.session.query(Flavors).all()
			for flavor in flavors:
				response['result']['flavors'].append(row2dict(flavor))
		
		return response
Esempio n. 14
0
def flavor_verify_install(flavor):
    # build the response
    response = {"response": "", "result": {"message": "", "flavor": {}}}

    # get the cluster configuration
    try:
        openstack = db.session.query(OpenStack).first()

        # what happens if they haven't configured it already?
        if not openstack:
            raise OpenStackConfiguration(
                "OpenStack configuration isn't complete.")
    except Exception as ex:
        # return error
        flavor_error_response(ex)

    # establish connection to openstack
    try:
        nova = nova_connection()
    except Exception as ex:
        # return error
        flavor_error_response(ex)

    # look up flavors
    try:
        targetflavor = None

        # look up the flavor by name and stop on it
        osflavors = nova.flavors.list()
        for osflavor in osflavors:
            if osflavor.name == flavor.name:
                targetflavor = osflavor
                break

    except:
        # no flavor found
        targetflavor = None

    # check for install needed
    install_flavor = False

    # check flavor specs match
    if targetflavor:
        if targetflavor.vcpus != flavor.vpus:  # vpus wrong
            install_flavor = True
        if targetflavor.disk != flavor.disk:  # disk size wrong
            install_flavor = True
        if targetflavor.ram != flavor.memory:  # memory wrong
            install_flavor = True

        # get the flavor network quota keys (if required)
        try:
            if flavor.network > 0:
                # get the flavor keys from openstack
                # throws not found if they don't exist
                osikeys = targetflavor.get_keys()

                # check quotas match
                if 'quota:inbound_average' in osikeys and 'quota:outbound_average' in osikeys:
                    if flavor.network != int(osikeys['quota:inbound_average']):
                        install_flavor = True
                    if flavor.network != int(
                            osikeys['quota:outbound_average']):
                        install_flavor = True
                else:
                    install_flavor = True
            else:
                # do nothing
                pass

        except:
            # just force install
            install_flavor = True

    else:
        # no flavor found
        install_flavor = True
        app.logger.info("Flavor not found.")

    # install the flavor
    if install_flavor:
        if targetflavor:
            try:
                # remove the old flavor
                nova.flavors.delete(targetflavor.id)
            except:
                app.logger.info(
                    "Could not remove the old flavor=(%s) from the OpenStack cluster."
                    % flavor.name)

        # referenced from ticket #80
        # create the new flavor
        targetflavor = nova.flavors.create(flavor.name,
                                           flavor.memory,
                                           flavor.vpus,
                                           flavor.disk,
                                           flavorid='auto',
                                           ephemeral=0,
                                           swap=0,
                                           rxtx_factor=1.0,
                                           is_public=True)

        # set bandwidth
        targetflavor.set_keys({"quota:inbound_average": flavor.network})
        targetflavor.set_keys({"quota:outbound_average": flavor.network})

        app.logger.info("Installed flavor=(%s) into the OpenStack cluster." %
                        flavor.name)

    # update the flavor database with id
    flavor.osid = targetflavor.id
    flavor.update(flavor)

    # response
    response['response'] = "success"
    response['result']['message'] = "Flavor added."
    response['result']['flavor'] = row2dict(flavor)

    return response
Esempio n. 15
0
def image_verify_install(image):
    # build the response
    response = {"response": "", "result": {"message": "", "image": {}}}

    # get the cluster configuration
    openstack = db.session.query(OpenStack).first()

    # no openstack settings
    if not openstack:
        response['response'] = "success"
        response['result'][
            'message'] = "OpenStack configuration isn't complete."
        return response

    # authenticate with keystone to get glance endpoint
    keystone = ksclient.Client(auth_url=openstack.authurl,
                               username=openstack.osusername,
                               password=openstack.ospassword,
                               tenant_id=openstack.tenantid)

    # establish connection to glance
    glance_endpoint = keystone.service_catalog.url_for(service_type='image')
    glance = glanceclient.Client('1',
                                 endpoint=glance_endpoint,
                                 token=keystone.auth_token,
                                 timeout=10)

    # flags, bleh. glance, double bleh.
    install_image = False
    installed = False

    # see if we have the image already
    try:
        osimage = glance.images.get(image.osid)

        if osimage:
            app.logger.info("OpenStack shows an image matching image=(%s)" %
                            image.name)

        # os image was deleted somehow
        if osimage.deleted == True:
            osimage = None
            app.logger.info("OpenStack shows image=(%s) has been deleted." %
                            image.name)
            install_image = True

    except Exception as ex:
        # thrown if we don't have it installed
        osimage = None
        app.logger.info("Image=(%s) needs to be installed." % (image.name))
        install_image = True

    # check if it's old
    if osimage:
        # check update times
        pattern = '%Y-%m-%dT%H:%M:%S'
        image_epoch = int(
            time.mktime(time.strptime(osimage.created_at, pattern)))

        # if we have an old copy in openstack, we delete it and install new
        if image_epoch < image.updated:
            app.logger.info(
                "Deleting image=(%s) from the OpenStack cluster.  It was old."
                % image.name)
            install_image = True
            glance.images.delete(image.osid)
        else:
            installed = True

    # check if we have to install
    if install_image:
        # test for a local url and set location
        if image.local_url == "" or image.local_url is None:
            location = image.url
        else:
            location = image.local_url

        # try to install with either local or remote image
        try:
            osimage = glance.images.create(
                name=image.name,
                is_public=False,
                disk_format=image.diskformat,
                container_format=image.containerformat,
                location=location)

            # check if installed
            if osimage:
                installed = True

        except Exception as ex:
            # glance threw an error, so we assume it was because of the URL
            app.logger.info(
                "Trying to use the remote URL for installing the image=(%s)" %
                image.name)

            if location == image.local_url:
                # failure to grab local copy, so try original
                try:
                    osimage = glance.images.create(
                        name=image.name,
                        is_public=False,
                        disk_format=image.diskformat,
                        container_format=image.containerformat,
                        location=image.url)

                    # check if installed
                    if osimage:
                        app.logger.info("Image=(%s) was installed." %
                                        image.name)
                        installed = True

                except Exception as ex:
                    # nothing can be done
                    installed == False
                    app.logger.info("Glance can't install image=(%s): %s" %
                                    (image.name, ex))
            else:
                # we already tried the original URL and it's not working
                installed == False
                app.logger.info("Glance can't install image=(%s)." %
                                image.name)

    # check if we got it installed
    if installed == False:
        try:
            app.logger.info(
                "The image=(%s) is being deleted from the OpenStack cluster." %
                image.name)
            glance.images.delete(image.osid)
        except Exception as ex:
            # image.osid didn't exist, or image wasn't installed
            pass

        # zero this image on the appliance
        image.osid = ""
        image.active = 0
        image.update()

        # response
        response['response'] = "error"
        response['result']['image'] = row2dict(image)
        response['result'][
            'message'] = "Failed to install image into the cluster."

        app.logger.error(
            "Failed to install image=(%s) into the OpenStack cluster." %
            (image.name))

    else:
        # install success! update updated time for image
        pattern = '%Y-%m-%dT%H:%M:%S'
        image.updated = int(
            time.mktime(time.strptime(osimage.created_at, pattern)))
        image.osid = osimage.id
        image.update()

        # response
        response['response'] = "success"
        response['result']['image'] = row2dict(image)
        response['result']['message'] = "Image installed."

    return response
Esempio n. 16
0
def flavor_verify_install(flavor):
    # build the response
    response = {"response": "", "result": {"message": "", "flavor": {}}}

    # get the cluster configuration
    try:
        openstack = db.session.query(OpenStack).first()
        # what happens if they haven't configured it already?
        if not openstack:
            raise OpenStackConfiguration(
                "OpenStack configuration isn't complete.")
    except Exception as ex:
        # return error
        flavor_error_response(ex)

    # establish connection to openstack
    try:
        nova = nova_connection()
    except Exception as ex:
        # return error
        flavor_error_response(ex)

    # look up flavors
    try:
        # look up the flavor by name and stop on it
        targetflavor = nova.flavors.get(flavor.osid)

    except:
        # flavor could not be retreived by osid
        targetflavor = None
        osflavors = nova.flavors.list()
        for osflavor in osflavors:
            if osflavor.name == flavor.name:
                if flavor.is_same_as_osflavor(osflavor):
                    targetflavor = osflavor
                    break

    if not targetflavor:
        try:
            # referenced from ticket #80
            # create the new flavor
            targetflavor = nova.flavors.create(flavor.name,
                                               flavor.memory,
                                               flavor.vpus,
                                               flavor.disk,
                                               flavorid='auto',
                                               ephemeral=0,
                                               swap=0,
                                               rxtx_factor=1.0,
                                               is_public=True)
        except nova_exceptions.Forbidden:
            response['response'] = "forbidden"
            response['result'][
                'message'] = "Can't install flavor due to lack of permissions for tenant user."
            return response
        except Exception as ex:
            response['response'] = "error"
            response['result'][
                'message'] = "Error installing flavor inside OpenStack. %s" % ex
            return response

        # set bandwidth
        targetflavor.set_keys({"quota:inbound_average": flavor.network_down})
        targetflavor.set_keys({"quota:outbound_average": flavor.network_up})

        app.logger.info("Installed flavor=(%s) into the OpenStack cluster." %
                        flavor.name)

    # update the flavor database with id
    flavor.update(osid=targetflavor.id, installed=True)

    # response
    response['response'] = "success"
    response['result']['message'] = "Flavor added."
    response['result']['flavor'] = row2dict(flavor)

    return response
Esempio n. 17
0
    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_instances(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
Esempio n. 18
0
def image_verify_install(image):
	# build the response
	response = {"response": "", "result": {"message": "", "image": {}}}

	# get the cluster configuration
	openstack = db.session.query(OpenStack).first()

	# no openstack settings
	if not openstack:
		response['response'] = "success"
		response['result']['message'] = "OpenStack configuration isn't complete."
		return response

	# authenticate with keystone to get glance endpoint
	keystone = ksclient.Client(
		auth_url = openstack.authurl, 
		username = openstack.osusername, 
		password = openstack.ospassword, 
		tenant_id = openstack.tenantid
	)

	# establish connection to glance
	glance_endpoint = keystone.service_catalog.url_for(service_type='image')
	glance = glanceclient.Client('1', endpoint=glance_endpoint, token=keystone.auth_token, timeout=10)

	# flags, bleh. glance, double bleh.
	install_image = False
	installed = False

	# see if we have the image already
	try:
		osimage = glance.images.get(image.osid)

		if osimage:
			app.logger.info("OpenStack shows an image matching image=(%s)" % image.name)
		
		# os image was deleted somehow
		if osimage.deleted == True:
			osimage = None
			app.logger.info("OpenStack shows image=(%s) has been deleted." % image.name)
			install_image = True

	except Exception as ex:
		# thrown if we don't have it installed
		osimage = None
		app.logger.info("Image=(%s) needs to be installed." % (image.name))
		install_image = True

	# check if it's old
	if osimage:
		# check update times
		pattern = '%Y-%m-%dT%H:%M:%S'
		image_epoch = int(time.mktime(time.strptime(osimage.created_at, pattern)))

		# if we have an old copy in openstack, we delete it and install new
		if image_epoch < image.updated:
			app.logger.info("Deleting image=(%s) from the OpenStack cluster.  It was old." % image.name)
			install_image = True
			glance.images.delete(image.osid)
		else:
			installed = True

	# check if we have to install
	if install_image:
		# test for a local url and set location
		if image.local_url == "" or image.local_url is None:
			location = image.url
		else:
			location = image.local_url

		# try to install with either local or remote image
		try:
			osimage = glance.images.create(
				name = image.name, 
				is_public = False, 
				disk_format = image.diskformat, 
				container_format = image.containerformat,
				location = location
			)

			# check if installed
			if osimage:
				installed = True
		
		except Exception as ex:
			# glance threw an error, so we assume it was because of the URL
			app.logger.info("Trying to use the remote URL for installing the image=(%s)" % image.name)
			
			if location == image.local_url:
				# failure to grab local copy, so try original
				try:
					osimage = glance.images.create(
						name = image.name, 
						is_public = False, 
						disk_format = image.diskformat, 
						container_format = image.containerformat,
						location = image.url
					)

					# check if installed
					if osimage:
						app.logger.info("Image=(%s) was installed." % image.name)
						installed = True

				except Exception as ex:
					# nothing can be done
					installed == False
					app.logger.info("Glance can't install image=(%s): %s" % (image.name, ex))
			else:
				# we already tried the original URL and it's not working
				installed == False
				app.logger.info("Glance can't install image=(%s)." % image.name)

	# check if we got it installed
	if installed == False:
		try:
			app.logger.info("The image=(%s) is being deleted from the OpenStack cluster." % image.name)
			glance.images.delete(image.osid)
		except Exception as ex:
			# image.osid didn't exist, or image wasn't installed
			pass

		# zero this image on the appliance
		image.osid = ""
		image.active = 0
		image.update()

		# response
		response['response'] = "error"
		response['result']['image'] = row2dict(image)
		response['result']['message'] = "Failed to install image into the cluster."

		app.logger.error("Failed to install image=(%s) into the OpenStack cluster." % (image.name))

	else:
		# install success! update updated time for image
		pattern = '%Y-%m-%dT%H:%M:%S'
		image.updated = int(time.mktime(time.strptime(osimage.created_at, pattern)))
		image.osid = osimage.id
		image.update()

		# response
		response['response'] = "success"
		response['result']['image'] = row2dict(image)
		response['result']['message'] = "Image installed."

	return response
Esempio n. 19
0
def flavor_verify_install(flavor):
	# build the response
	response = {"response": "", "result": {"message": "", "flavor": {}}}
	

	# get the cluster configuration
	try:
		openstack = db.session.query(OpenStack).first()
		
		# what happens if they haven't configured it already?
		if not openstack:
			raise OpenStackConfiguration("OpenStack configuration isn't complete.")
	except Exception as ex:
		# return error
		flavor_error_response(ex)
	
	# establish connection to openstack
	try:
		nova = nova_connection()
	except Exception as ex:
		# return error
		flavor_error_response(ex)

	# look up flavors		
	try:
		targetflavor = None

		# look up the flavor by name and stop on it
		osflavors = nova.flavors.list()
		for osflavor in osflavors:
			if osflavor.name == flavor.name:
				targetflavor = osflavor
				break
	
	except:
		# no flavor found
		targetflavor = None


	# check for install needed
	install_flavor = False

	# check flavor specs match
	if targetflavor:
		if targetflavor.vcpus != flavor.vpus: # vpus wrong
			install_flavor = True
		if targetflavor.disk != flavor.disk: # disk size wrong
			install_flavor = True 
		if targetflavor.ram != flavor.memory: # memory wrong
			install_flavor = True

		# get the flavor network quota keys (if required)
		try:
			if flavor.network > 0:
				# get the flavor keys from openstack
				# throws not found if they don't exist
				osikeys = targetflavor.get_keys()

				# check quotas match
				if 'quota:inbound_average' in osikeys and 'quota:outbound_average' in osikeys:
					if flavor.network != int(osikeys['quota:inbound_average']):
						install_flavor = True
					if flavor.network != int(osikeys['quota:outbound_average']):
						install_flavor = True
				else:
					install_flavor = True
			else:
				# do nothing
				pass

		except:
			# just force install
			install_flavor = True

	else:
		# no flavor found
		install_flavor = True
		app.logger.info("Flavor not found.")

	# install the flavor
	if install_flavor:
		if targetflavor:
			try:
				# remove the old flavor
				nova.flavors.delete(targetflavor.id)
			except:
				app.logger.info("Could not remove the old flavor=(%s) from the OpenStack cluster." % flavor.name)

		# referenced from ticket #80 
		# create the new flavor
		targetflavor = nova.flavors.create(
			flavor.name,
			flavor.memory,
			flavor.vpus,
			flavor.disk,
			flavorid='auto',
			ephemeral=0,
			swap=0,
			rxtx_factor=1.0,
			is_public=True
		)

		# set bandwidth
		targetflavor.set_keys({"quota:inbound_average": flavor.network})
		targetflavor.set_keys({"quota:outbound_average": flavor.network})

		app.logger.info("Installed flavor=(%s) into the OpenStack cluster." % flavor.name)

	# update the flavor database with id
	flavor.osid = targetflavor.id
	flavor.update(flavor)

	# response
	response['response'] = "success"
	response['result']['message'] = "Flavor added."
	response['result']['flavor'] = row2dict(flavor)

	return response
Esempio n. 20
0
def flavor_verify_install(flavor):
	# build the response
	response = {"response": "", "result": {"message": "", "flavor": {}}}

	# get the cluster configuration
	try:
		openstack = db.session.query(OpenStack).first()
		# what happens if they haven't configured it already?
		if not openstack:
			raise OpenStackConfiguration("OpenStack configuration isn't complete.")
	except Exception as ex:
		# return error
		flavor_error_response(ex)
	
	# establish connection to openstack
	try:
		nova = nova_connection()
	except Exception as ex:
		# return error
		flavor_error_response(ex)

	# look up flavors
	try:
		# look up the flavor by name and stop on it
		targetflavor = nova.flavors.get(flavor.osid)
	
	except:
		# flavor could not be retreived by osid
		targetflavor = None
		osflavors = nova.flavors.list()
		for osflavor in osflavors:
			if osflavor.name == flavor.name:
				if flavor.is_same_as_osflavor(osflavor):
					targetflavor = osflavor
					break

	if not targetflavor:
		try:
			# referenced from ticket #80 
			# create the new flavor
			targetflavor = nova.flavors.create(
				flavor.name,
				flavor.memory,
				flavor.vpus,
				flavor.disk,
				flavorid='auto',
				ephemeral=0,
				swap=0,
				rxtx_factor=1.0,
				is_public=True
			)
		except nova_exceptions.Forbidden:
			response['response'] = "forbidden"
			response['result']['message'] = "Can't install flavor due to lack of permissions for tenant user."
			return response
		except Exception as ex:
			response['response'] = "error"
			response['result']['message'] = "Error installing flavor inside OpenStack. %s" % ex
			return response

		# set bandwidth
		targetflavor.set_keys({"quota:inbound_average": flavor.network_down})
		targetflavor.set_keys({"quota:outbound_average": flavor.network_up})

		app.logger.info("Installed flavor=(%s) into the OpenStack cluster." % flavor.name)

	# update the flavor database with id
	flavor.update(osid=targetflavor.id, installed=True)

	# response
	response['response'] = "success"
	response['result']['message'] = "Flavor added."
	response['result']['flavor'] = row2dict(flavor)

	return response
Esempio n. 21
0
def configure_flavors_detail(flavor_id):
	# get the matching flavor
	flavor = db.session.query(Flavors).filter_by(id=flavor_id).first()

	# clear settings cache
	Status().flush()

	# enable/diskable
	if 'enable' in request.form.keys():
		flavor.update(active=int(request.form['enable']))

	# set ask
	if 'ask' in request.form.keys():
		flavor.update(ask=int(request.form['ask']))

	# set max-instances
	if 'max-instances' in request.form.keys():
		flavor.update(max_instances=int(request.form['max-instances']))

	# install pool flavor
	if 'install' in request.form.keys():
		# let's see what we can break, er install
		try:
			if not flavor:
				response = jsonify({"response": "error", "result": {"message": "Flavor %s not found." % flavor_id }})
				response.status_code = 404
				return response

			# we are told to install
			if int(request.form['install']):
				response = flavor_verify_install(flavor)
				if not response['response'] == 'success':
					raise Exception(response['result']['message'])
				
				if flavor.ask > 0:
					flavor.update(active=True)
				else:
					flavor.update(active=False)
			else:
				# we are told to uninstall (install=0)
				response = flavor_uninstall(flavor)
				if not response['response'] == 'success':
					raise Exception(response['result']['message'])

				flavor.update(installed=False, active=False, osid=None)

		except Exception as e:
			response = jsonify({"response": "error", "result": {"message": str(e)}})
			response.status_code = 403
			return response

	# set instance state to match flavor's state
	instances = Instances()
	instances.toggle(flavor.id, flavor.active)

	# update the ask prices on the openstack cluster using metadata
	try:
		# get current ask price on openstack and update
		flavor.save()

	# warn because we couldn't update the ask price that's set on openstack
	except nova_exceptions.Forbidden:
		app.logger.warning('No permissions to update price of flavor "{0}".'.format(
											 flavor.name))
		return response
	
	# handle any other exception while talking to openstack
	except Exception as e:
		app.logger.warning('Error updating price of flavor "{0}": {1}.'.format(
											 flavor.name, str(e)))

	return jsonify({"response": "success", "flavor": row2dict(flavor)})