def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ key = '/commissaire/cluster/{0}/restart'.format(name) if not util.etcd_cluster_exists(name): self.logger.info( 'Restart GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return status, error = cherrypy.engine.publish('store-get', key)[0] self.logger.debug('Etcd Response: {0}'.format(status)) if error: # Return "204 No Content" if we have no status, # meaning no restart is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(( 'Restart GET requested for {0} but no restart ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = ClusterRestart(**json.loads(status.value))
def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ key = '/commissaire/cluster/{0}/upgrade'.format(name) try: if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Upgrade GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return status = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(status)) except etcd.EtcdKeyNotFound: # Return "204 No Content" if we have no status, # meaning no upgrade is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(( 'Upgrade GET requested for {0} but no upgrade ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = ClusterUpgrade(**json.loads(status.value))
def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return try: cluster_upgrade = ClusterUpgrade.retrieve(name) self.logger.debug('Found ClusterUpgrade for {0}'.format(name)) except: # Return "204 No Content" if we have no status, # meaning no upgrade is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(( 'Upgrade GET requested for {0} but no upgrade ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = cluster_upgrade
def on_put(self, req, resp, name): """ Handles the creation of a new Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being created. :type name: str """ # PUT is idempotent, and since there's no body to this request, # there's nothing to conflict with. The request should always # succeed, even if we didn't actually do anything. if util.etcd_cluster_exists(self.store, name): self.logger.info( 'Creation of already exisiting cluster {0} requested.'.format( name)) else: key = util.etcd_cluster_key(name) cluster = Cluster(status='ok', hostset=[]) etcd_resp = self.store.set(key, cluster.to_json(secure=True)) self.logger.info( 'Created cluster {0} per request.'.format(name)) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) resp.status = falcon.HTTP_201
def on_put(self, req, resp, name): """ Handles the creation of a new Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being created. :type name: str """ # PUT is idempotent, and since there's no body to this request, # there's nothing to conflict with. The request should always # succeed, even if we didn't actually do anything. if util.etcd_cluster_exists(name): self.logger.info( 'Creation of already exisiting cluster {0} requested.'.format( name)) else: key = util.etcd_cluster_key(name) cluster = Cluster(status='ok', hostset=[]) etcd_resp, _ = cherrypy.engine.publish( 'store-save', key, cluster.to_json(secure=True))[0] self.logger.info('Created cluster {0} per request.'.format(name)) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) resp.status = falcon.HTTP_201
def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ if not util.etcd_cluster_exists(name): self.logger.info( 'Restart GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return try: store_manager = cherrypy.engine.publish('get-store-manager')[0] cluster_restart = store_manager.get(ClusterRestart.new(name=name)) except: # Return "204 No Content" if we have no status, # meaning no restart is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(( 'Restart GET requested for {0} but no restart ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = cluster_restart
def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ key = '/commissaire/cluster/{0}/restart'.format(name) try: if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Restart GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return status = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(status)) except etcd.EtcdKeyNotFound: # Return "204 No Content" if we have no status, # meaning no restart is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(('Restart GET requested for {0} but no restart ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = ClusterRestart(**json.loads(status.value))
def on_get(self, req, resp, name): """ Handles GET (or "status") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ key = '/commissaire/cluster/{0}/upgrade'.format(name) if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade GET requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return status, error = cherrypy.engine.publish('store-get', key)[0] self.logger.debug('Etcd Response: {0}'.format(status)) if error: # Return "204 No Content" if we have no status, # meaning no upgrade is in progress. The client # can't be expected to know that, so it's not a # client error (4xx). self.logger.debug(('Upgrade GET requested for {0} but no upgrade ' 'has ever been executed.').format(name)) resp.status = falcon.HTTP_204 return resp.status = falcon.HTTP_200 req.context['model'] = ClusterUpgrade(**json.loads(status.value))
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. try: store_manager = cherrypy.engine.publish('get-store-manager')[0] cluster_upgrade = store_manager.get(ClusterUpgrade.new(name=name)) self.logger.debug('Found ClusterUpgrade for {0}'.format(name)) if not cluster_upgrade.finished_at: self.logger.debug( 'Cluster {0} upgrade already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_upgrade return except: # This means one doesn't already exist. pass # TODO: Move to a poll? store_manager = cherrypy.engine.publish('get-store-manager')[0] args = (store_manager.clone(), name, 'upgrade') p = Process(target=clusterexec, args=args) p.start() self.logger.debug('Started upgrade in clusterexecpool for {0}'.format( name)) cluster_upgrade = ClusterUpgrade.new( name=name, status='in_process', started_at=datetime.datetime.utcnow().isoformat() ) store_manager = cherrypy.engine.publish('get-store-manager')[0] store_manager.save(cluster_upgrade) resp.status = falcon.HTTP_201 req.context['model'] = cluster_upgrade
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. try: cluster_upgrade = ClusterUpgrade.retrieve(name) self.logger.debug('Found ClusterUpgrade for {0}'.format(name)) if not cluster_upgrade.finished_at: self.logger.debug( 'Cluster {0} upgrade already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_upgrade return except: # This means one doesn't already exist. pass # TODO: Move to a poll? p = Process(target=clusterexec, args=(name, 'upgrade')) p.start() self.logger.debug('Started upgrade in clusterexecpool for {0}'.format( name)) cluster_upgrade_default = { 'status': 'in_process', 'upgraded': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_upgrade = ClusterUpgrade(**cluster_upgrade_default) cluster_upgrade.save(name) resp.status = falcon.HTTP_201 req.context['model'] = cluster_upgrade
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Restart PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. key = '/commissaire/cluster/{0}/restart'.format(name) etcd_resp, error = cherrypy.engine.publish('store-get', key)[0] if not error: self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) cluster_restart = ClusterRestart(**json.loads(etcd_resp.value)) if not cluster_restart.finished_at: self.logger.debug( 'Cluster {0} restart already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_restart return # TODO: Move to a poll? p = Process(target=clusterexec, args=(name, 'restart')) p.start() self.logger.debug('Started restart in clusterexecpool for {0}'.format( name)) cluster_restart_default = { 'status': 'in_process', 'restarted': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_restart = ClusterRestart(**cluster_restart_default) cherrypy.engine.publish('store-save', key, cluster_restart.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_restart
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Restart PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. key = '/commissaire/cluster/{0}/restart'.format(name) etcd_resp, error = cherrypy.engine.publish('store-get', key)[0] if not error: self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) cluster_restart = ClusterRestart(**json.loads(etcd_resp.value)) if not cluster_restart.finished_at: self.logger.debug( 'Cluster {0} restart already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_restart return # TODO: Move to a poll? p = Process(target=clusterexec, args=(name, 'restart')) p.start() self.logger.debug( 'Started restart in clusterexecpool for {0}'.format(name)) cluster_restart_default = { 'status': 'in_process', 'restarted': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_restart = ClusterRestart(**cluster_restart_default) cherrypy.engine.publish('store-save', key, cluster_restart.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_restart
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Restart PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. key = '/commissaire/cluster/{0}/restart'.format(name) try: etcd_resp = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) cluster_restart = ClusterRestart(**json.loads(etcd_resp.value)) if not cluster_restart.finished_at: self.logger.debug( 'Cluster {0} restart already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_restart return except etcd.EtcdKeyNotFound: pass POOLS['clusterexecpool'].spawn(clusterexec.clusterexec, name, 'restart', self.store) self.logger.debug( 'Started restart in clusterexecpool for {0}'.format(name)) cluster_restart_default = { 'status': 'in_process', 'restarted': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_restart = ClusterRestart(**cluster_restart_default) self.store.set(key, cluster_restart.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_restart
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster restart. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being restarted. :type name: str """ # Make sure the cluster name is valid. if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Restart PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress, return the current # status with response code 200 OK. key = '/commissaire/cluster/{0}/restart'.format(name) try: etcd_resp = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) cluster_restart = ClusterRestart(**json.loads(etcd_resp.value)) if not cluster_restart.finished_at: self.logger.debug( 'Cluster {0} restart already in progress'.format(name)) resp.status = falcon.HTTP_200 req.context['model'] = cluster_restart return except etcd.EtcdKeyNotFound: pass POOLS['clusterexecpool'].spawn( clusterexec.clusterexec, name, 'restart', self.store) self.logger.debug('Started restart in clusterexecpool for {0}'.format( name)) cluster_restart_default = { 'status': 'in_process', 'restarted': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_restart = ClusterRestart(**cluster_restart_default) self.store.set(key, cluster_restart.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_restart
def on_delete(self, req, resp, name): """ Handles the deletion of a Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being deleted. :type name: str """ resp.body = '{}' if not util.etcd_cluster_exists(name): self.logger.info( 'Deleting for non-existent cluster {0} requested.'.format( name)) resp.status = falcon.HTTP_404 else: self.store.delete(util.etcd_cluster_key(name)) resp.status = falcon.HTTP_200 self.logger.info('Deleted cluster {0} per request.'.format(name))
def on_delete(self, req, resp, name): """ Handles the deletion of a Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being deleted. :type name: str """ resp.body = '{}' if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Deleting for non-existent cluster {0} requested.'.format( name)) resp.status = falcon.HTTP_404 else: self.store.delete(util.etcd_cluster_key(name)) resp.status = falcon.HTTP_410 self.logger.info( 'Deleted cluster {0} per request.'.format(name))
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ data = req.stream.read().decode() try: args = json.loads(data) upgrade_to = args['upgrade_to'] except (KeyError, ValueError): resp.status = falcon.HTTP_400 return # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress and the requested version # matches, return the current status with response code 200 OK. # If the requested version conflicts with the operation in progress, # return the current status with response code 409 Conflict. key = '/commissaire/cluster/{0}/upgrade'.format(name) etcd_resp, error = cherrypy.engine.publish('store-get', key)[0] self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) if not error: cluster_upgrade = ClusterUpgrade(**json.loads(etcd_resp.value)) if not cluster_upgrade.finished_at: if cluster_upgrade.upgrade_to == upgrade_to: self.logger.debug( 'Cluster {0} upgrade to {1} already in progress'. format(name, upgrade_to)) resp.status = falcon.HTTP_200 else: self.logger.debug( 'Cluster upgrade to {0} requested while ' 'upgrade to {1} was already in progress'.format( upgrade_to, cluster_upgrade.upgrade_to)) resp.status = falcon.HTTP_409 req.context['model'] = cluster_upgrade return # FIXME: How do I pass 'upgrade_to'? p = Process(target=clusterexec, args=(name, 'upgrade')) p.start() self.logger.debug( 'Started upgrade in clusterexecpool for {0}'.format(name)) cluster_upgrade_default = { 'status': 'in_process', 'upgrade_to': upgrade_to, 'upgraded': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_upgrade = ClusterUpgrade(**cluster_upgrade_default) cherrypy.engine.publish('store-save', key, cluster_upgrade.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_upgrade
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a tree image deployment across a Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster undergoing deployment. :type name: str """ data = req.stream.read().decode() try: args = json.loads(data) version = args['version'] except (KeyError, ValueError): resp.status = falcon.HTTP_400 return # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Deploy PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return store_manager = cherrypy.engine.publish('get-store-manager')[0] # If the operation is already in progress and the requested version # matches, return the current status with response code 200 OK. # If the requested version conflicts with the operation in progress, # return the current status with response code 409 Conflict. try: cluster_deploy = store_manager.get(ClusterDeploy.new(name=name)) self.logger.debug('Found ClusterDeploy for {0}'.format(name)) if not cluster_deploy.finished_at: if cluster_deploy.version == version: self.logger.debug( 'Cluster {0} deployment to {1} already in progress'. format(name, version)) resp.status = falcon.HTTP_200 else: self.logger.debug( 'Cluster deployment to {0} requested while ' 'deployment to {1} was already in progress'. format(version, cluster_deploy.version)) resp.status = falcon.HTTP_409 req.context['model'] = cluster_deploy return except: pass args = (store_manager.clone(), name, 'deploy', {'version': version}) p = Process(target=clusterexec, args=args) p.start() self.logger.debug( 'Started deployment to {0} in clusterexecpool for {1}'.format( version, name)) cluster_deploy = ClusterDeploy.new( name=name, status='in_process', started_at=datetime.datetime.utcnow().isoformat() ) store_manager.save(cluster_deploy) resp.status = falcon.HTTP_201 req.context['model'] = cluster_deploy
def on_put(self, req, resp, address): """ Handles the creation of a new Host. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param address: The address of the Host being requested. :type address: str """ try: # Extract what we need from the input data. # Don't treat it as a skeletal host record. req_data = req.stream.read() req_body = json.loads(req_data.decode()) ssh_priv_key = req_body['ssh_priv_key'] # Cluster member is optional. cluster_name = req_body.get('cluster', None) except (KeyError, ValueError): self.logger.info( 'Bad client PUT request for host {0}: {1}'. format(address, req_data)) resp.status = falcon.HTTP_400 return key = util.etcd_host_key(address) try: etcd_resp = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) # Check if the request conflicts with the existing host. existing_host = Host(**json.loads(etcd_resp.value)) if existing_host.ssh_priv_key != ssh_priv_key: resp.status = falcon.HTTP_409 return if cluster_name: try: assert util.etcd_cluster_has_host( self.store, cluster_name, address) except (AssertionError, KeyError): resp.status = falcon.HTTP_409 return # Request is compatible with the existing host, so # we're done. (Not using HTTP_201 since we didn't # actually create anything.) resp.status = falcon.HTTP_200 req.context['model'] = existing_host return except etcd.EtcdKeyNotFound: pass host_creation = { 'address': address, 'ssh_priv_key': ssh_priv_key, 'os': '', 'status': 'investigating', 'cpus': -1, 'memory': -1, 'space': -1, 'last_check': None } # Verify the cluster exists, if given. Do it now # so we can fail before writing anything to etcd. if cluster_name: if not util.etcd_cluster_exists(self.store, cluster_name): resp.status = falcon.HTTP_409 return host = Host(**host_creation) new_host = self.store.set(key, host.to_json(secure=True)) INVESTIGATE_QUEUE.put((host_creation, ssh_priv_key)) # Add host to the requested cluster. if cluster_name: util.etcd_cluster_add_host(self.store, cluster_name, address) resp.status = falcon.HTTP_201 req.context['model'] = Host(**json.loads(new_host.value))
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a Cluster upgrade. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster being upgraded. :type name: str """ data = req.stream.read().decode() try: args = json.loads(data) upgrade_to = args['upgrade_to'] except (KeyError, ValueError): resp.status = falcon.HTTP_400 return # Make sure the cluster name is valid. if not util.etcd_cluster_exists(self.store, name): self.logger.info( 'Upgrade PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress and the requested version # matches, return the current status with response code 200 OK. # If the requested version conflicts with the operation in progress, # return the current status with response code 409 Conflict. key = '/commissaire/cluster/{0}/upgrade'.format(name) try: etcd_resp = self.store.get(key) self.logger.debug('Etcd Response: {0}'.format(etcd_resp)) cluster_upgrade = ClusterUpgrade(**json.loads(etcd_resp.value)) if not cluster_upgrade.finished_at: if cluster_upgrade.upgrade_to == upgrade_to: self.logger.debug( 'Cluster {0} upgrade to {1} already in progress'. format(name, upgrade_to)) resp.status = falcon.HTTP_200 else: self.logger.debug( 'Cluster upgrade to {0} requested while ' 'upgrade to {1} was already in progress'. format(upgrade_to, cluster_upgrade.upgrade_to)) resp.status = falcon.HTTP_409 req.context['model'] = cluster_upgrade return except etcd.EtcdKeyNotFound: pass # FIXME: How do I pass 'upgrade_to'? POOLS['clusterexecpool'].spawn( clusterexec.clusterexec, name, 'upgrade', self.store) self.logger.debug('Started upgrade in clusterexecpool for {0}'.format( name)) cluster_upgrade_default = { 'status': 'in_process', 'upgrade_to': upgrade_to, 'upgraded': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_upgrade = ClusterUpgrade(**cluster_upgrade_default) self.store.set(key, cluster_upgrade.to_json()) resp.status = falcon.HTTP_201 req.context['model'] = cluster_upgrade
def on_put(self, req, resp, name): """ Handles PUT (or "initiate") requests for a tree image deployment across a Cluster. :param req: Request instance that will be passed through. :type req: falcon.Request :param resp: Response instance that will be passed through. :type resp: falcon.Response :param name: The name of the Cluster undergoing deployment. :type name: str """ data = req.stream.read().decode() try: args = json.loads(data) version = args['version'] except (KeyError, ValueError): resp.status = falcon.HTTP_400 return # Make sure the cluster name is valid. if not util.etcd_cluster_exists(name): self.logger.info( 'Upgrade PUT requested for nonexistent cluster {0}'.format( name)) resp.status = falcon.HTTP_404 return # If the operation is already in progress and the requested version # matches, return the current status with response code 200 OK. # If the requested version conflicts with the operation in progress, # return the current status with response code 409 Conflict. try: cluster_deploy = ClusterDeploy.retrieve(name) self.logger.debug('Found ClusterDeploy for {0}'.format(name)) if not cluster_deploy.finished_at: if cluster_deploy.version == version: self.logger.debug( 'Cluster {0} deployment to {1} already in progress'. format(name, version)) resp.status = falcon.HTTP_200 else: self.logger.debug( 'Cluster deployment to {0} requested while ' 'upgrade to {1} was already in progress'. format(version, cluster_deploy.version)) resp.status = falcon.HTTP_409 req.context['model'] = cluster_deploy return except: pass p = Process(target=clusterexec, args=(name, 'upgrade', {'version': version})) p.start() self.logger.debug('Started upgrade in clusterexecpool for {0}'.format( name)) cluster_deploy_default = { 'status': 'in_process', 'version': version, 'deployed': [], 'in_process': [], 'started_at': datetime.datetime.utcnow().isoformat(), 'finished_at': None } cluster_deploy = ClusterDeploy(**cluster_deploy_default) cluster_deploy.save(name) resp.status = falcon.HTTP_201 req.context['model'] = cluster_deploy