コード例 #1
0
    def get(self):
        # look up instances that were updated more than 15 minutes ago
        instances = Instance.get_older_than(900)

        # loop through results and mark returned instances as 'inactive'
        if instances:
            for instance in instances:
                if instance.state == 1 and instance.reserved == False:
                    logging.info("Marking instance=(%s) stale." %
                                 instance.name)
                    instance.state = 0
                    instance.put()

                    # notification channel
                    if instance.token:
                        channel_message(instance.token, "stale")

        # look up instances that were updated more than 24 hours ago
        instances = Instance.get_older_than(86400)

        # loop through results and delete them
        if instances:
            for instance in instances:
                # whack instances that are decomissioned or never been started
                if instance.state == 7 or instance.state < 3:
                    logging.info("Deleting stale instance=(%s)." %
                                 instance.name)
                    instance.key.delete()

                    # notification channel
                    if instance.token:
                        channel_message(instance.token, "delete")
        return
コード例 #2
0
ファイル: taskhandlers.py プロジェクト: StackMonkey/site
	def get(self):
		# look up instances that were updated more than 15 minutes ago
		instances = Instance.get_older_than(900)

		# loop through results and mark returned instances as 'inactive'
		if instances:
			for instance in instances:
				if instance.state == 1 and instance.reserved == False:
					logging.info("Marking instance=(%s) stale." % instance.name)
					instance.state = 0
					instance.put()

					# notification channel
					if instance.token:
						channel_message(instance.token, "stale")

		# look up instances that were updated more than 24 hours ago
		instances = Instance.get_older_than(86400)

		# loop through results and delete them
		if instances:
			for instance in instances:
				# whack instances that are decomissioned or never been started 
				if instance.state == 7 or instance.state < 3:
					logging.info("Deleting stale instance=(%s)." % instance.name)
					instance.key.delete()

					# notification channel
					if instance.token:
						channel_message(instance.token, "delete")
		return
コード例 #3
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # look up instances, then patch them for hotstart support
        pinstances = []
        instances = Instance.get_all()
        for instance in instances:
            try:
                username_patch = instance.user.get().username
            except:
                username_patch = "#HOTSTART#"  # no self

            pinstance = {
                "name": instance.name,
                "status": instance.status,
                "username_patch": username_patch,
                "created": instance.created,
                "expires": instance.expires,
                "key": instance.key
            }
            pinstances.append(pinstance)

        params = {'instances': pinstances}

        return self.render_template('admin/instances.html', **params)
コード例 #4
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self, name=None):
        # check token
        token = self.request.get('token')
        if token != "":
            user_info = User.get_by_token(token)

            if user_info:
                db_instances = Instance.get_all()

                # work around index warning/errors using a .filter() in models.py
                instances = []
                for db_instance in db_instances:
                    # limit to instances the user has started
                    if db_instance.user == user_info.key:
                        instances.append(db_instance)
                params = {
                    'user_name': user_info.username,
                    'instances': instances
                }

                self.response.headers['Content-Type'] = "application/json"
                return self.render_template('api/instances.json', **params)

        # no token, no user, no data
        params = {
            "response": "fail",
            "message": "must include [token] parameter with a valid token"
        }

        self.response.status = '402 Payment Required'
        self.response.status_int = 402
        self.response.headers['Content-Type'] = "application/json"
        return self.render_template('api/response.json', **params)
コード例 #5
0
	def get(self, token = None):
		# lookup up bid
		bid = InstanceBid.get_by_token(token)
		if not bid:
			self.add_message("Instance reservation token %s has expired." % token, 'error')
			return self.redirect_to('lab-launcher')

		# grab the instance
		instance = Instance.get_by_token(token)
		if not instance:
			self.add_message("Could not find an instance with token %s." % token, 'error')
			return self.redirect_to('lab-launcher')

		# setup channel to do page refresh
		channel_token = token
		refresh_channel = channel.create_channel(channel_token)

		# params build out
		params = {
			'bid': bid,
			'instance': instance,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}

		return self.render_template('lab/bid.html', **params)
コード例 #6
0
	def get(self, instance_name = None):

		# get the instance, build the response type
		instance = Instance.get_by_name(instance_name)
		self.response.headers['Content-Type'] = "application/json"

		# if no instance, then show error
		if not instance:
			params['message'] = "Instance not found."
			self.response.set_status(404)
			return self.render_template('api/response.json', **params)

		# load the instance's meta data, if any
		if instance.meta:
			meta = json.loads(instance.meta)
		else:
			meta = json.loads('{}')

		# build response
		params = {
			"instance": instance,
			"meta": meta
		}

		params['response'] = "success"
		self.response.headers['Content-Type'] = 'application/json'
		
		return self.render_template('api/instance.json', **params)
コード例 #7
0
	def get(self, demo_name = None, token = None):
		# grab the instance
		instance = Instance.get_by_token(token)
		if not instance:
			self.add_message("That instance cannot be found.", 'error')
			return self.redirect_to('demos', demo_name=demo_name)

		# setup channel to do page refresh
		channel_token = token
		refresh_channel = channel.create_channel(channel_token)

		# hack in time max for timer
		instance.data_max = int(instance.expires - int(instance.started.strftime('%s')))

		# dict the meta
		if instance.meta:
			instance.meta_dict = json.loads(instance.meta)
		else:
			instance.meta_dict = {}

		params = {
			'instance': instance,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}
		return self.render_template('site/demos/%s_instance.html' % demo_name, **params)
コード例 #8
0
    def get(self, cloud_id=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # get the cloud in question
        cloud = Cloud.get_by_id(long(cloud_id))

        # bail if cloud doesn't exist or not owned by this user
        if not cloud or cloud.owner != user_info.key:
            return self.redirect_to('account-clouds')

        # look up cloud's instances
        instances = Instance.get_by_cloud(cloud.key)

        # setup channel to do page refresh
        channel_token = user_info.key.urlsafe()
        refresh_channel = channel.create_channel(channel_token)

        # params build out
        params = {
            'cloud': cloud,
            'instances': instances,
            'refresh_channel': refresh_channel,
            'channel_token': channel_token
        }

        return self.render_template('cloud/edit.html', **params)
コード例 #9
0
ファイル: cloudhandlers.py プロジェクト: StackMonkey/site
	def get(self, cloud_id = None):
		# lookup user's auth info
		user_info = User.get_by_id(long(self.user_id))
		
		# get the cloud in question
		cloud = Cloud.get_by_id(long(cloud_id))

		# bail if cloud doesn't exist or not owned by this user
		if not cloud or cloud.owner != user_info.key:
			return self.redirect_to('account-clouds')

		# look up cloud's instances
		instances = Instance.get_by_cloud(cloud.key)

		# setup channel to do page refresh
		channel_token = user_info.key.urlsafe()
		refresh_channel = channel.create_channel(channel_token)

		# params build out
		params = {
			'cloud': cloud,
			'instances': instances, 
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}

		return self.render_template('cloud/edit.html', **params)
コード例 #10
0
ファイル: cloudhandlers.py プロジェクト: StackMonkey/site
	def delete(self, cloud_id = None):
		# lookup user's auth info
		user_info = User.get_by_id(long(self.user_id))
		
		# pull the entry from the db
		cloud = Cloud.get_by_id(long(cloud_id))

		# check the number of instances
		count = Instance.get_count_by_cloud(cloud.key)

		# deny if it has instances
		if count > 0:
			self.add_message('You may not delete a cloud with instances!', 'info')

		# if we found it and own it, delete
		elif cloud and cloud.owner == user_info.key:
			cloud.key.delete()
			self.add_message('Cloud successfully deleted!', 'success')
		else:
			self.add_message('Cloud was not deleted.  Something went horribly wrong somewhere!', 'warning')

		# hangout for a second
		time.sleep(1)

		# use the channel to tell the browser we are done and reload
		channel_token = self.request.get('channel_token')
		channel.send_message(channel_token, 'reload')
		return
コード例 #11
0
    def delete(self, cloud_id=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # pull the entry from the db
        cloud = Cloud.get_by_id(long(cloud_id))

        # check the number of instances
        count = Instance.get_count_by_cloud(cloud.key)

        # deny if it has instances
        if count > 0:
            self.add_message('You may not delete a cloud with instances!',
                             'info')

        # if we found it and own it, delete
        elif cloud and cloud.owner == user_info.key:
            cloud.key.delete()
            self.add_message('Cloud successfully deleted!', 'success')
        else:
            self.add_message(
                'Cloud was not deleted.  Something went horribly wrong somewhere!',
                'warning')

        # hangout for a second
        time.sleep(1)

        # use the channel to tell the browser we are done and reload
        channel_token = self.request.get('channel_token')
        channel.send_message(channel_token, 'reload')
        return
コード例 #12
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def get(self, name):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # look up user's instances
        instance = Instance.get_by_name(name)

        self.response.headers['Content-Type'] = "text/plain"

        if not instance:
            params = {"contents": "Waiting on serial console output..."}
            return self.render_template('instance/console.txt', **params)

        try:
            # update list of instances we have
            http = httplib2.Http()
            url = '%s/api/instance/%s/console?token=%s' % (
                config.fastener_host_url, name, config.fastener_api_token)
            response, content = http.request(url, 'GET')
            stuff = json.loads(content)

            params = {"contents": stuff['contents']}
        except Exception as ex:
            params = {"contents": "Waiting on serial console output..."}

        return self.render_template('instance/console.txt', **params)
コード例 #13
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self, name=None):
        # check token
        token = self.request.get('token')
        if token != "":
            user_info = User.get_by_token(token)

            if user_info:
                instance = Instance.get_by_name(name)

                try:
                    if instance.user == user_info.key:

                        # make the instance call to the control box
                        http = httplib2.Http(timeout=10)
                        url = '%s/api/instance/%s/start?token=%s' % (
                            config.fastener_host_url, name,
                            config.fastener_api_token)

                        # pull the response back TODO add error handling
                        response, content = http.request(url,
                                                         'GET',
                                                         None,
                                                         headers={})

                        # update if google returns pending
                        if json.loads(content)['status'] == "PENDING":
                            instance.status = "STAGING"
                            instance.started = datetime.datetime.now()
                            instance.put()

                        params = {'instance': instance}

                        self.response.headers[
                            'Content-Type'] = "application/json"
                        return self.render_template('api/instance.json',
                                                    **params)

                except Exception as ex:
                    print "error %s" % ex
                    print "instance %s not found or not in TERMINATED state" % name

                params = {
                    "response":
                    "fail",
                    "message":
                    "[token] read access denied or instance not TERMINATED"
                }
                return self.render_template('api/response.json', **params)

        # no token, no user, no data
        params = {
            "response": "fail",
            "message": "must include [token] parameter with a valid token"
        }

        self.response.status = '402 Payment Required'
        self.response.status_int = 402
        self.response.headers['Content-Type'] = "application/json"
        return self.render_template('api/response.json', **params)
コード例 #14
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self, name=None):
        # define possible status
        statuses = [
            "PROVISIONING",
            "STAGING",
            "CONFIGURING",
            "RUNNING",
            "STOPPING",
            "TERMINATED",
            "BUILDING"  # lucidworks status for building out box
        ]

        status = self.request.get('status')
        if status.upper() not in statuses:
            params = {
                "response": "fail",
                "message": "unknown status %s" % status
            }
            return self.render_template('api/response.json', **params)

        password = self.request.get('password')
        if password != "":
            instance = Instance.get_by_password(password)

            try:
                if instance.name == name:
                    instance.status = status
                    instance.put()

                    self.response.headers['Content-Type'] = "application/json"
                    params = {'instance': instance}
                    return self.render_template('api/instance.json', **params)

                else:
                    params = {
                        "response": "fail",
                        "message": "unknown instance name %s" % name
                    }
                    return self.render_template('api/response.json', **params)

            except Exception as ex:
                params = {
                    "response": "fail",
                    "message": "exception reached %s" % ex
                }
                return self.render_template('api/response.json', **params)
        else:
            params = {
                "response": "fail",
                "message": "[password] write status access denied"
            }
            return self.render_template('api/response.json', **params)
コード例 #15
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self):
        db_instances = Instance.get_all()

        # work around index warning/errors using a .filter() in models.py
        statuses = []
        for db_instance in db_instances:
            # limit to instances the user has started
            statuses.append(db_instance.status[0])

        params = {'statuses': statuses}

        self.response.headers['Content-Type'] = "application/json"
        return self.render_template('api/instances.csv', **params)
コード例 #16
0
	def post(self):
		# paramters, assume failure, response type
		params = {}
		params['response'] = "error"
		self.response.headers['Content-Type'] = "application/json"

		# get appliance variables
		try:
			packet = json.loads(self.request.body)
			apitoken = packet['appliance']['apitoken']
		except:
			params['message'] = "You must submit a valid JSON object with a token."
			self.response.set_status(401)
			return self.render_template('api/response.json', **params)	
		
		# load the appliance
		appliance = Appliance.get_by_token(apitoken)

		if not appliance:
			params['message'] = "Token is not valid."
			self.response.set_status(401)
			return self.render_template('api/response.json', **params)

		if appliance.activated == False:
			# appliance not activated
			params['message'] = "Appliance has been disabled by pool controller. Please contact support."
			self.response.set_status(409)
			return self.render_template('api/response.json', **params)

		# update appliance info
		latitude = float(packet['appliance']['location']['latitude'])
		longitude = float(packet['appliance']['location']['longitude'])
		appliance.location = ndb.GeoPt(latitude, longitude)
		appliance.dynamicimages = bool(packet['appliance']['dynamicimages'])			
		appliance.put()

		# loop through instances being advertised for sale
		for appliance_instance in packet['instances']:
			# pass in appliance_instance and appliance object
			#logging.info("instance: %s" % appliance_instance['name'])
			instance = Instance.push(appliance_instance, appliance)

		# build parameter list
		params = {}
		params['response'] = "success"
		params['message'] = "Instances accepted for sale."
		self.response.headers['Content-Type'] = 'application/json'
		
		return self.render_template('api/response.json', **params)
コード例 #17
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def get(self, name):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # look up user's instances
        instance = Instance.get_by_name(name)

        if not instance:
            params = {}
            return self.redirect_to('instances-list', **params)

        if instance.renamed == None:
            instance.renamed = ""  # remap so template can address

        if instance.created < (datetime.datetime.now() -
                               datetime.timedelta(0, 600)):
            instance.expired = True
        else:
            instance.expired = False

        stream = Stream.get_by_id(instance.stream.id())

        if utils.read_cookie(self, "guide") == "closed":
            guide = False
        else:
            guide = True

        if instance.size == 1:
            instance_cores = 8
            instance_memory = 30
        elif instance.size == 2:
            instance_cores = 16
            instance_memory = 60
        else:
            instance_cores = 4
            instance_memory = 15

        params = {
            'guide': guide,
            'instance': instance,
            'stream': stream,
            'user_info': user_info,
            'instance_cores': instance_cores,
            'instance_memory': instance_memory
        }

        return self.render_template('instance/detail.html', **params)
コード例 #18
0
    def get(self, appliance_id=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # seek out the appliance in question
        appliance = Appliance.get_by_id(long(appliance_id))

        # bail if appliance doesn't exist user isn't the owner
        if not appliance or appliance.owner != user_info.key:
            return self.redirect_to('account-appliances')

        # find instances associated with this appliance
        instances = Instance.get_by_appliance(appliance.key)

        # render new appliance page
        parms = {'appliance': appliance, 'instances': instances}
        return self.render_template('appliance/view.html', **parms)
コード例 #19
0
ファイル: appliancehandlers.py プロジェクト: StackMonkey/site
    def get(self, appliance_id=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # seek out the appliance in question
        appliance = Appliance.get_by_id(long(appliance_id))

        # bail if appliance doesn't exist user isn't the owner
        if not appliance or appliance.owner != user_info.key:
            return self.redirect_to("account-appliances")

            # find instances associated with this appliance
        instances = Instance.get_by_appliance(appliance.key)

        # render new appliance page
        parms = {"appliance": appliance, "instances": instances}
        return self.render_template("appliance/view.html", **parms)
コード例 #20
0
	def get(self, instance_name = None):

		# get the instance, build the response type
		instance = Instance.get_by_name(instance_name)
		self.response.headers['Content-Type'] = "application/json"

		# if no instance, then show error
		if not instance:
			params['message'] = "Instance not found."
			self.response.set_status(404)
			return self.render_template('api/response.json', **params)

		params = {}
		params['response'] = "success"
		
		self.response.headers['Content-Type'] = 'application/json'
		
		return self.render_template('api/instance.json', **params)
コード例 #21
0
	def delete(self, token=None):
		bid = InstanceBid.get_by_token(token)

		# delete the bid
		if bid:
			bid.key.delete()

		# patch up the respective instance if it's not been started
		instance = Instance.get_by_token(token)

		if instance:
			# only patch instance if it's not been started
			if instance.state <= 1:
					instance.reserved = False
					instance.token = None
					instance.put()

		return
コード例 #22
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def delete(self, instance_id=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # delete instance
        instance = Instance.get_by_id(long(instance_id))
        slack.slack_message("Instance %s deleted for %s!" %
                            (instance.name, user_info.username))
        instance.key.delete()

        # hangout for a second
        if config.isdev:
            time.sleep(1)

        params = {
            "response": "success",
            "message": "instance %s deleted" % instance.name
        }
        return self.render_template('api/response.json', **params)
コード例 #23
0
	def get(self, token = None):
		# lookup up bid
		bid = InstanceBid.get_by_token(token)
		if not bid:
			self.add_message("Instance reservation token %s has expired." % token, 'error')
			return self.redirect_to('projects')

		# grab the project from the bid
		project = Project.get_by_id(bid.wisp.get().project.id())

		# grab the instance
		instance = Instance.get_by_token(token)
		if not instance:
			self.add_message("All available instance reservations are in use. Please try again in a few minutes.", 'error')
			return self.redirect_to('projects')

		# grab and render the README.md file
		content = urlfetch.fetch('http://10.0.1.80:8079/wisps/6048757061779456/README.md').content

		readme_html = bleach.clean(
			markdown.markdown(
				unicode(content, 'utf-8')
			), 
			config.bleach_tags,
			config.bleach_attributes
		)	

		# setup channel to do page refresh
		channel_token = token
		refresh_channel = channel.create_channel(channel_token)

		params = {
			'instance': instance,
			'bid': bid,
			'project': project,
			'readme_html': readme_html,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}
		return self.render_template('project/bid.html', **params)
コード例 #24
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def get(self, sid=None):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # redirect to a POST if we have a sid in the URL
        if sid and user_info.email:
            return self.post(sid)
        try:
            if not user_info.email or not user_info.name or not user_info.company:
                need_more_info = True
            else:
                need_more_info = False
        except:
            need_more_info = True

        # look up user's instances
        db_instances = Instance.get_all()

        # work around index warning/errors using a .filter() in models.py
        instances = []
        for db_instance in db_instances:
            # limit to instances the user has started
            if db_instance.user == user_info.key:
                if db_instance.renamed == None:
                    db_instance.renamed = ""
                instances.append(db_instance)

        streams = Stream.get_all()

        params = {
            'instances': instances,
            'num_instances': len(instances),
            'streams': streams,
            'user_id': self.user_id,
            'user_info': user_info,
            'sid': sid,
            'need_more_info': need_more_info
        }

        return self.render_template('instance/list.html', **params)
コード例 #25
0
	def get(self, token = None):
		# grab the instance
		instance = Instance.get_by_token(token)
		if not instance:
			self.add_message("Could not find an instance with token %s." % token, 'error')
			return self.redirect_to('lab-launcher')

		# hack in time max for timer
		instance.data_max = int(instance.expires - int(instance.started.strftime('%s')))

		# setup channel to do page refresh
		channel_token = token
		refresh_channel = channel.create_channel(channel_token)

		# params build out
		params = {
			'instance': instance,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}

		return self.render_template('lab/instance.html', **params)
コード例 #26
0
ファイル: cloudhandlers.py プロジェクト: StackMonkey/site
	def delete(self, cloud_id = None, instance_id = None):
		# hangout for a second
		time.sleep(1)

		# look up the instance
		instance = Instance.get_by_id(long(instance_id))

		if instance:
			cloud = instance.cloud
			if long(cloud.id()) == long(cloud_id):
				instance.cloud = None
				instance.put()
			else:
				self.add_message("Clouds don't match.", "error")
		else:
			self.add_message("Instance not found!", "error")

		# use the channel to tell the browser we are done and reload
		channel_token = self.request.get('channel_token')
		channel.send_message(channel_token, 'reload')

		return
コード例 #27
0
	def get(self, token=None):
		# response, type, cross posting
		params = {}
		self.response.headers['Content-Type'] = "application/json"
		self.response.headers['Access-Control-Allow-Origin'] = '*'

		# look for instance bid first
		bid = InstanceBid.get_by_token(token)

		if bid:
			# build out the response
			params['response'] = "success"
			params['message'] = "Reservation found by token."	
			params['instancebid'] = bid

			# return response
			self.response.set_status(201)
			return self.render_template('api/bid.json', **params)

		else:
			# look for instance
			instance = Instance.get_by_token(token)
			
			if instance:
				# build out the response
				params['response'] = "success"
				params['message'] = "Instance found by token."	
				params['instance'] = instance

				# return response
				self.response.set_status(201)
				return self.render_template('api/instancedetail.json', **params)
			
			else:
				# build out the error response
				params['response'] = "error"
				params['message'] = "No resources found by token."

				return self.render_template('api/response.json', **params)
コード例 #28
0
    def delete(self, cloud_id=None, instance_id=None):
        # hangout for a second
        time.sleep(1)

        # look up the instance
        instance = Instance.get_by_id(long(instance_id))

        if instance:
            cloud = instance.cloud
            if long(cloud.id()) == long(cloud_id):
                instance.cloud = None
                instance.put()
            else:
                self.add_message("Clouds don't match.", "error")
        else:
            self.add_message("Instance not found!", "error")

        # use the channel to tell the browser we are done and reload
        channel_token = self.request.get('channel_token')
        channel.send_message(channel_token, 'reload')

        return
コード例 #29
0
	def post(self):
		# request basics
		ip = self.request.remote_addr
		offset = self.request.get("offset")
		limit = self.request.get("limit")

		instances = Instance().get_all_offered()
		
		# add gravatar URLs
		for instance in instances:
			email = instance.appliance.get().owner.get().email
			gravatar_hash = md5.new(email.lower().strip()).hexdigest()
			instance.gravatar_url = "https://www.gravatar.com/avatar/%s" % gravatar_hash

		# build parameter list
		params = {
			'remote_ip': ip,
			'instances': instances
		}

		# return images via template
		self.response.headers['Content-Type'] = 'application/json'
		return self.render_template('api/instances.json', **params)
コード例 #30
0
ファイル: cloudhandlers.py プロジェクト: StackMonkey/site
	def get(self):
		# lookup user's auth info
		user_info = User.get_by_id(long(self.user_id))

		# look up appliances
		clouds = Cloud.get_by_user(user_info.key)

		# instance counts
		for cloud in clouds:
			count = Instance.get_count_by_cloud(cloud.key)
			cloud.instance_count = count

		# setup channel to do page refresh
		channel_token = user_info.key.urlsafe()
		refresh_channel = channel.create_channel(channel_token)

		# params build out
		params = {
			'clouds': clouds,
			'refresh_channel': refresh_channel,
			'channel_token': channel_token 
		}

		return self.render_template('cloud/list.html', **params)
コード例 #31
0
ファイル: adminhandlers.py プロジェクト: sudosoup/streams
    def get(self, name=None):
        # check token
        token = self.request.get('token')
        if token != "":
            user_info = User.get_by_token(token)

            if user_info:
                instance = Instance.get_by_name(name)

                try:
                    if instance.user == user_info.key:
                        params = {'instance': instance}
                        self.response.headers[
                            'Content-Type'] = "application/json"
                        return self.render_template('api/instance.json',
                                                    **params)
                except Exception as ex:
                    print "error %s" % ex
                    print "instance %s not found" % name

                params = {
                    "response": "fail",
                    "message": "[token] read access denied"
                }
                return self.render_template('api/response.json', **params)

        # no token, no user, no data
        params = {
            "response": "fail",
            "message": "must include [token] parameter with a valid token"
        }

        self.response.status = '402 Payment Required'
        self.response.status_int = 402
        self.response.headers['Content-Type'] = "application/json"
        return self.render_template('api/response.json', **params)
コード例 #32
0
    def get(self):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # look up appliances
        clouds = Cloud.get_by_user(user_info.key)

        # instance counts
        for cloud in clouds:
            count = Instance.get_count_by_cloud(cloud.key)
            cloud.instance_count = count

        # setup channel to do page refresh
        channel_token = user_info.key.urlsafe()
        refresh_channel = channel.create_channel(channel_token)

        # params build out
        params = {
            'clouds': clouds,
            'refresh_channel': refresh_channel,
            'channel_token': channel_token
        }

        return self.render_template('cloud/list.html', **params)
コード例 #33
0
ファイル: apihandlers.py プロジェクト: StackMonkey/site
	def post(self, instance_name):
		# paramters, assume failure, response type
		params = {}
		params['response'] = "error"
		self.response.headers['Content-Type'] = "application/json"

		# request basics
		ip = self.request.remote_addr

		try:
			body = json.loads(self.request.body)
			instance_schema = schemas['InstanceSchema'](**body['instance'])
			appliance_schema = schemas['ApplianceSchema'](**body['appliance'])

			# try to authenticate appliance
			if not Appliance.authenticate(appliance_schema.apitoken.as_dict()):
				logging.error("%s is using an invalid token(%s) or appliance deactivated."
					% (ip, appliance_schema.apitoken.as_dict()))
				return error_response(self, "Token is not valid.", 401, params)

			# fetch appliance and instance
			appliance = Appliance.get_by_token(appliance_schema.apitoken.as_dict())

			instance = Instance.get_by_name_appliance(
				instance_schema.name.as_dict(), 
				appliance.key
			)

			# if instance doesn't already exist, create it
			if not instance:
				wisp = Wisp.get_user_default(appliance.owner)
				if not wisp:
					wisp = Wisp.get_system_default()
				instance = Instance(wisp=wisp.key)

			# wrap instance into api shim in order to translate values from structure
			# of api to structure of model. I hope at some point in the future the two
			# models are similar enough so we can entirely drop this shim
			instance_shim = InstanceApiShim(instance)

			# update instance with values from post
			ApiSchemaHelper.fill_object_from_schema(
				instance_schema, instance_shim)

			# associate instance with it's appliance
			instance_shim.appliance = appliance

		except Exception as e:
			return error_response(self, 'Error in creating or updating instance from '
				'post data, with message {0}'.format(str(e)), 500, {})


		# update local instance
		instance.put()

		# update appliance ip address hint
		if instance.state > 3 and instance.ipv4_address:
			appliance.ipv4enabled = True
		if instance.state > 3 and instance.ipv6_address:
			appliance.ipv6enabled = True
		appliance.put()

		# sleep for dev
		if config.debug:
			time.sleep(1)

		# send update information to channel
		if instance.token:

			output = {
				"name": instance.name,
				"token": instance.token,
				"state": instance.state,
			}
			channel.send_message(instance.token, json.dumps(output))		

		# pop a reload just in case user is on their cloud page
		if instance.owner:
			user_info = User.get_by_id(long(instance.owner.id()))
			channel.send_message(user_info.key.urlsafe(), "reload")

		# convert bid to instance
		# check if there is an instance bid reservation on this instance
		instancebid = InstanceBid.get_by_instance(instance.key)
		if instancebid:
			# check for a bid callback_url (entered in the callback field on the launcher)
			if instancebid.callback_url > "":
				# put the callback into the instance
				instance.callback_url = instancebid.callback_url
			
			elif instancebid.wisp:
				# otherwise, get the wisp's callback URL	
				callback_url = instancebid.wisp.get().callback_url
			
				# if the wisp has an empty callback URL, populate the instance with the wisp's bid details
				if callback_url == "" or callback_url == None:
					instance.wisp = instancebid.wisp
					instance.owner = instancebid.wisp.get().owner
					instance.cloud = instancebid.cloud
				else:
					# we have a custom callback in the wisp itself, so move to instance
					instance.callback_url = callback_url

			# update the instance
			instance.put()

			# delete the instance reservation
			instancebid.key.delete()

		# proxy custom callback
	
		"""
		BEGIN CODE CALLOUT
		"""
		# August 24, 2014
		#
		# The following code retrieves content from a remote server and proxies it to 
		# an appliance for starting an instance. It is at this point an anonymous user's
		# callback pattern is most venerable to being monitored and manipulated.
		# 
		# The author of this software issues a warrant canary tweet to @stackape which 
		# should appear on the 1st of each month indicating the absence of a gag order
		# having been issued to StackMonkey, Utter.io, or Kord Campbell.
		#
		# Please monitor the code block between BEGIN CODE CALLOUT and END CODE CALLOUT 
		# if the canary tweet does not appear on schedule. Please monitor any callback
		# file's retrieval patterns if the canary tweet does not appear on schedule.
		# Please report any findings to the community sections of the project/site.
		#
		# Remember, the code is Open Source. Use that fact to the community's advantage.
		# 
		# The warrant canary will likely be your only indication a change has possibly
		# taken place to the system.  These changes may or may not enable a government 
		# agency to intercept and monitor instances using a custom URL callback.
		#
		# Kord Campbell
		#
		if instance.callback_url:
			try:
				result = urlfetch.fetch(instance.callback_url, deadline=5)
			except Exception as ex:
				logging.error("Error fetching callback URL content.")
				instance.console_output = "Error fetching callback url=(%s)'s' content. %s" % (instance.callback_url, ex)
				instance.put()

				# user may be sitting on an instance reservation here, so reload the page
				# this will force the handler to redirect the user to the instance page
				channel.send_message(instance.token, "reload")
				return error_response(self, "Error fetching callback URL content.", 401, params)

			# return content retrieved from callback URL if the JSON returned by this method includes
			# a callback_url in the data, the appliance will follow the URL and will not call this API 
			# again during the life of the instance.
			self.response.headers['Content-Type'] = 'application/json'
			self.response.write(json.dumps(json.loads(result.content), sort_keys=True, indent=2))
			
			# return from here	
			return

		"""
		END CODE CALLOUT
		"""

		# at this point we have one of two scenarios:
		# 1. an external instance start (registered user with appliance, sans instancebid)
		# 2. registered user using a normal wisp WITHOUT a callback_url

		# grab the instance's wisp
		if instance.wisp:
			# if instance is using a wisp
			wisp = Wisp.get_by_id(instance.wisp.id())
		else:
			# no wisp on instance
			wisp = Wisp.get_user_default(instance.owner)

		# deliver default system wisp if none (external instance start)
		if not wisp:
			wisp = Wisp.get_system_default()

		# load wisp image
		if not wisp.use_dynamic_image:
			image = wisp.image.get()
		else:
			image = wisp.get_dynamic_image()

		# pop the ssh_key into an array
		if wisp.ssh_key:
			ssh_keys = []
			for line in iter(wisp.ssh_key.splitlines()):
				ssh_keys.append(line)
		else:
			ssh_keys = [""]

		# 
		# pop the post creation script into an array
		if wisp.post_creation:
			post_creation = []
			for line in iter(wisp.post_creation.splitlines()):
				post_creation.append(line)
		else:
			post_creation = [""]

		# some of replay's magic - need docs on this
		start_params = schemas['InstanceStartParametersSchema']()
		data = {
			'image': image,
			'callback_url': wisp.callback_url if wisp.callback_url else "",
			'ssh_keys': ssh_keys,
			'post_create': post_creation}
		ApiSchemaHelper.fill_schema_from_object(start_params, data)

		self.response.set_status(200)
		self.response.headers['Content-Type'] = 'application/json'

		# write dictionary as json string
		self.response.out.write(json.dumps(
				# retrieve dict from schema
				start_params.as_dict()))
コード例 #34
0
	def post(self, instance_name):
		# paramters, assume failure, response type
		params = {}
		params['response'] = "fail"
		self.response.headers['Content-Type'] = "application/json"

		# get appliance variables
		try:
			packet = json.loads(self.request.body)
			apitoken = packet['appliance']['apitoken']
		except:
			params['message'] = "You must submit a valid JSON object with a token."
			self.response.set_status(401)
			return self.render_template('api/response.json', **params)	
		
		# load the appliance
		appliance = Appliance.get_by_token(apitoken)

		if not appliance:
			params['message'] = "Token is not valid."
			self.response.set_status(401)
			return self.render_template('api/response.json', **params)

		if appliance.activated == False:
			# appliance not activated
			params['message'] = "Appliance has been disabled by pool controller. Please contact support."
			self.response.set_status(409)
			return self.render_template('api/response.json', **params)

		# pull out the appliance's instance
		try:
			appliance_instance = packet['instance']
		except:
			params['response'] = "fail"
			params['result'] = "JSON instance data not found."
			self.response.set_status(404)
			return self.render_template('api/response.json', **params)
		
		# grab the instance name and check the url
		try:
			name = appliance_instance['name']
			# same name?
			if instance_name != name:
				raise
		except:
			params['response'] = "fail"
			params['result'] = "JSON instance name needs to match resource URI."
			self.response.set_status(401)
			self.response.headers['Content-Type'] = 'application/json'
			return self.render_template('api/response.json', **params)			

		# grab the rest of the instance info
		try:
			# grab the rest of appliance POST data
			flavor_name = appliance_instance['flavor']
			ask = appliance_instance['ask']
			expires = datetime.fromtimestamp(appliance_instance['expires'])
			address = appliance_instance['address'] # bitcoin address
		except:
			params['response'] = "fail"
			params['result'] = "JSON instance data not found.  Flavor, ask, expires or address missing."
			self.response.set_status(404)
			return self.render_template('api/response.json', **params)

		# look up the pool's version of this instance
		instance = Instance.get_by_name_appliance(name, appliance.key)

		# create a new instance for this appliance because we've never seen it
		if not instance:
			instance = Instance().push(appliance_instance, appliance)
			wisp = Wisp.get_user_default(appliance.owner)
			instance.wisp = wisp.key
			instance.put()

		# grab the instance's wisp
		if instance.wisp:
			wisp = Wisp.get_by_id(instance.wisp.id())
		else:
			# we need a decent fallback for how to boot an image without a wisp
			wisp = Wisp.get_user_default(instance.owner)

		# get the value or return None if not present
		dynamic_image_url = wisp.dynamic_image_url if wisp.dynamic_image_url > "" else None
		callback_url = wisp.callback_url if wisp.callback_url > "" else None
		image = wisp.image.get().name if wisp.image else None
		
		# pop the ssh_key script into an array
		if wisp.ssh_key:
			ssh_key = []
			for line in iter(wisp.ssh_key.splitlines()):
				ssh_key.append(line)
		else:
			ssh_key = [""]

		# pop the post creation script into an array
		if wisp.post_creation:
			post_creation = []
			for line in iter(wisp.post_creation.splitlines()):
				post_creation.append(line)
		else:
			post_creation = [""]

		# load the instance info back into the response
		params = {
			'response': "success",
			'instance_name': name,
			'image': image,
			'dynamic_image_url': dynamic_image_url,
			'callback_url': callback_url,
			'ssh_key': ssh_key,
			'post_creation': post_creation 
		}

		self.response.headers['Content-Type'] = 'application/json'
		return self.render_template('api/instances.json', **params)
コード例 #35
0
ファイル: apihandlers.py プロジェクト: StackMonkey/site
	def put(self, instance_name = None):
		# disable csrf check in basehandler
		csrf_exempt = True

		# paramters, assume failure, response type
		params = {}
		params['response'] = "error"
		self.response.headers['Content-Type'] = "application/json"

		# get the instance, build the response type
		instance = Instance.get_by_name(instance_name)
		self.response.headers['Content-Type'] = "application/json"		

		# if no instance, then show error
		if not instance:
			params['message'] = "Instance not found."
			self.response.set_status(404)
			return self.render_template('api/response.json', **params)
		else:
			# load the instance's meta data, if any
			if instance.meta:
				meta = json.loads(instance.meta)
			else:
				meta = json.loads('{}')

		# load the json from the call
		try:
			body = json.loads(self.request.body)

			# loop through key space and set meta data
			for key in body:
				meta[key] = body[key]

			# dump back into the db
			instance.meta = json.dumps(meta)
			instance.put()

		except Exception as e:
			params['message'] = "An error was encountered with parsing meta key values: %s." % str(e)
			self.response.set_status(500)
			return self.render_template('api/response.json', **params)

		# send update information to channel
		if instance.token:
			output = {
				"name": instance.name,
				"token": instance.token,
				"state": instance.state,
				"meta": meta
			}
			channel.send_message(instance.token, json.dumps(output))	

		# build response
		params = {
			"instance": instance,
			"meta": json.loads(instance.meta)
		}
		params['response'] = "success"
		self.response.headers['Content-Type'] = 'application/json'
		
		return self.render_template('api/instance.json', **params)
コード例 #36
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def get(self, sid):
        # know the user
        user_info = User.get_by_id(long(self.user_id))

        # check if we have their email
        if not user_info.email:
            self.add_message(
                'Please update your email address before starting an instance!',
                'warning')
            return self.redirect_to('account-settings')

        # look up user's instances
        db_instances = Instance.get_all()

        # check the user's limits
        instance_count = 0
        for db_instance in db_instances:
            # limit to instances the user has started
            if db_instance.user == user_info.key:
                instance_count = instance_count + 1

        # warn and redirect if limit is reached
        if (instance_count + 1) > user_info.max_instances:
            self.add_message(
                'Instance limit reached. This account may only start %s instances. Please delete an existing instance to start a new one!'
                % user_info.max_instances, 'warning')
            return self.redirect_to('instances-list')

        # get stream
        stream = Stream.get_by_sid(sid)

        try:
            size = stream.instance_size
        except:
            size = 0

        ## HOT START
        # check for a hot start
        instances = Instance.get_hotstarts()

        for instance in instances:

            # fiveminutesago depends on number of seconds at end of this     ***
            fiveminutesago = datetime.datetime.now() - datetime.timedelta(
                0, 900)

            # if this hotstart instance has a matching sid, assign and redirect to it
            if instance.created < fiveminutesago and instance.stream.get(
            ).sid == stream.sid and instance.status == "RUNNING":
                # map to user
                instance.user = user_info.key
                instance.hotstart = False
                instance.put()

                self.add_message(
                    'Instance assigned! Use login buttons to access %s.' %
                    stream.name, 'success')
                slack.slack_message("Instance type %s assigned for %s!" %
                                    (stream.name, user_info.username))
                return self.redirect_to('instance-detail', name=instance.name)
        #
        ## TOH TRATS

        # make the instance call to the control box
        http = httplib2.Http(timeout=10)

        # where and who created it
        if config.isdev:
            iuser = "******" % ("dev", user_info.username)
        else:
            iuser = "******" % ("prod", user_info.username)

        url = '%s/api/stream/%s?token=%s&user=%s&size=%s' % (
            config.fastener_host_url, sid, config.fastener_api_token, iuser,
            size)

        try:
            # pull the response back TODO add error handling
            response, content = http.request(url, 'POST', None, headers={})
            gcinstance = json.loads(content)
            name = gcinstance['instance']
            password = gcinstance['password']

            if name == "failed":
                raise Exception("Instance start failed.")

            # set up an instance (note there are two ways to create an instance - see below)
            instance = Instance(name=name,
                                status="PROVISIONING",
                                user=user_info.key,
                                stream=stream.key,
                                size=size,
                                password=password,
                                expires=datetime.datetime.now() +
                                datetime.timedelta(0, 604800),
                                started=datetime.datetime.now())
            instance.put()

            slack.slack_message("Instance type %s created for %s!" %
                                (stream.name, user_info.username))

            # give the db a second to update
            if config.isdev:
                time.sleep(1)

            self.add_message(
                'Instance created! Give the system a few minutes to start %s.'
                % stream.name, 'success')

            params = {'name': name}
            return self.redirect_to('instance-detail', **params)

        except:
            self.add_message(
                'The system is currently busy with other instances. Please try again in a few minutes.',
                'warning')
            return self.redirect_to('instances-list')
コード例 #37
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def post(self, sid=None):  # a POST here is a create instance event
        # know the user
        user_info = User.get_by_id(long(self.user_id))

        if sid and user_info.email:

            # get form values
            stream = Stream.get_by_sid(sid)

            try:
                size = stream.instance_size
            except:
                size = 0

            # look up user's instances
            db_instances = Instance.get_all()

            # check the user's limits
            instance_count = 0
            for db_instance in db_instances:
                # limit to instances the user has started
                if db_instance.user == user_info.key:
                    instance_count = instance_count + 1

            # warn and redirect if limit is reached
            if (instance_count + 1) > user_info.max_instances:
                self.add_message(
                    'Instance limit reached. This account may only start %s instances. Please delete an existing instance to start a new one!'
                    % user_info.max_instances, 'warning')
                return self.redirect_to('instances-list')

            ## HOT START
            # check for a hot start
            instances = Instance.get_hotstarts()

            for instance in instances:
                # fiveminutesago depends on number of seconds at end of this     ***
                fiveminutesago = datetime.datetime.now() - datetime.timedelta(
                    0, 900)

                # if this hotstart instance has a matching sid, assign and redirect to it
                if instance.created < fiveminutesago and instance.stream.get(
                ).sid == stream.sid and instance.status == "RUNNING":
                    # map to user
                    instance.user = user_info.key
                    instance.hotstart = False
                    instance.put()

                    self.add_message(
                        'Instance assigned! Use login buttons to access %s.' %
                        stream.name, 'success')
                    slack.slack_message("Instance type %s assigned for %s!" %
                                        (stream.name, user_info.username))
                    return self.redirect_to('instance-detail',
                                            name=instance.name)
            #
            ## TRATS TOH

            # make the instance call handle
            http = httplib2.Http(timeout=10)

            # where and who created it (labels for google cloud console)
            if config.isdev:
                iuser = "******" % ("dev", user_info.username.lower())
            else:
                iuser = "******" % ("prod", user_info.username.lower())

            # build url to create new instance from stream
            url = '%s/api/stream/%s?token=%s&user=%s&size=%s' % (
                config.fastener_host_url, sid, config.fastener_api_token,
                iuser, size)

            try:
                # pull the response back TODO add error handling
                response, content = http.request(url, 'POST', None, headers={})
                gcinstance = json.loads(content)
                name = gcinstance['instance']
                password = gcinstance['password']

                if name == "failed":
                    raise Exception("Instance start failed.")

                # set up an instance
                instance = Instance(name=name,
                                    status="PROVISIONING",
                                    user=user_info.key,
                                    stream=stream.key,
                                    size=size,
                                    password=password,
                                    expires=datetime.datetime.now() +
                                    datetime.timedelta(0, 604800),
                                    started=datetime.datetime.now())
                instance.put()

                slack.slack_message("Instance type %s created for %s!" %
                                    (stream.name, user_info.username))

                # give the db a second to update
                if config.isdev:
                    time.sleep(1)

                self.add_message(
                    'Instance created! Grab some coffee and wait for %s to start.'
                    % stream.name, 'success')

                params = {'name': name}
                return self.redirect_to('instance-detail', **params)

            except:
                self.add_message(
                    'The system is currently busy with other instances. Please try again in a few minutes.',
                    'warning')
                return self.redirect_to('instances-list')

        else:
            # email update sumbission
            if not self.form.validate():
                self.add_message(
                    "There were errors validating your email address.",
                    "error")
                return self.get()

            email = self.form.email.data.strip()

            user_info = User.get_by_id(long(self.user_id))
            user_info.email = email.strip()
            user_info.put()

            if len(email) > 3 and not config.isdev:
                name = user_info.name
                try:
                    mc = MarketoClient(config.munchkin_id, config.mclient_id,
                                       config.mclient_secret)
                    try:
                        first = name.split()[0]
                    except:
                        first = ""

                    try:
                        last = name.split()[1]
                    except:
                        last = ""

                    try:
                        company = user_info.company
                    except:
                        company = "None"

                    leads = [{
                        "email": user_info.email,
                        "firstName": first,
                        "lastName": last,
                        "company": company,
                        "leadSource": config.mclient_leadSource
                    }]
                    lead = mc.execute(
                        method='push_lead',
                        leads=leads,
                        lookupField='email',
                        programName=config.mclient_programName,
                        programStatus=config.mclient_programStatus)

                except Exception as ex:
                    slack.slack_message(
                        "Marketo lead create failed because %s." % ex)

            slack.slack_message(
                "We got %s to update their email for instance launch!" %
                user_info.username)

            self.add_message("Thank you! Your email has been updated.",
                             'success')

            # redirect back to GET on list, but with a sid AND email in place this time to create
            if sid:
                return self.redirect_to('streams-start3', sid=sid)
            else:
                return self.redirect_to('instances-list')
コード例 #38
0
ファイル: instancehandlers.py プロジェクト: sudosoup/streams
    def get(self, name, command):
        # lookup user's auth info
        user_info = User.get_by_id(long(self.user_id))

        # get instance
        instance = Instance.get_by_name(name)

        if not instance:
            params = {}
            return self.redirect_to('instances-list', **params)
            slack.slack_message(
                "request for an instance we can't find - SPAMSPAMSPAM")

        else:
            # check user owns it or user is admin
            if user_info.admin != True and long(instance.user.id()) != long(
                    self.user_id):
                params = {
                    "response": "failure",
                    "message":
                    "instance %s not modifiable by calling user" % name
                }
                self.response.set_status(500)
                slack.slack_message("%s doesn't own %s" %
                                    (user_info.username, name))

            else:
                # start the instance
                if command == "start" and instance.status != "RUNNING":
                    slack.slack_message("firing up %s" % instance.name)
                    try:
                        instance.started = datetime.datetime.now()
                        instance.tender_action = "START"
                        instance.put()

                        params = {
                            "response":
                            "success",
                            "message":
                            "Instance %s marked to be started." % instance.name
                        }
                        slack.slack_message(
                            "updated db for %s with %s" %
                            (instance.name, instance.tender_action))
                    except Exception as ex:
                        params = {"response": "failure", "message": "%s" % ex}

                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/response.json', **params)

                # add ssh_key to instance
                elif command == "addkey":
                    # make the instance call to the control box
                    http = httplib2.Http(timeout=10)
                    url = '%s/api/instance/%s/addkey?token=%s&ssh_key=%s&username=%s' % (
                        config.fastener_host_url, name,
                        config.fastener_api_token,
                        urllib.quote(user_info.ssh_key), user_info.username)

                    try:
                        # pull the response back TODO add error handling
                        response, content = http.request(url,
                                                         'GET',
                                                         None,
                                                         headers={})

                        # delete if google returns pending
                        if json.loads(content)['status'] == "SUCCESS":
                            params = {
                                "response": "success",
                                "message":
                                "instance %s updated with key" % name
                            }
                        else:
                            params = {
                                "response": "failure",
                                "message":
                                "instance %s operation failure" % name
                            }
                            response.set_status(500)
                    except:
                        params = {
                            "response": "failure",
                            "message": "instance %s failure" % name
                        }

                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/response.json', **params)

                # just the status
                elif command == "status":
                    params = {"instance": instance}
                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/instance.json', **params)

                # delete the instance - C'est la vie
                elif command == "delete":
                    instance.key.delete()  # let the tender script delete it
                    params = {
                        "response": "success",
                        "message": "Instance marked to be deleted."
                    }

                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/response.json', **params)

                # rename it
                elif command == "rename":
                    renamed = self.request.get('renamed')
                    instance.renamed = renamed
                    instance.put()

                    params = {"instance": instance}
                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/instance.json', **params)

                else:
                    params = {
                        "response": "failure",
                        "message": "bad command, skippy"
                    }
                    self.response.set_status(500)
                    self.response.headers['Content-Type'] = "application/json"
                    return self.render_template('api/response.json', **params)