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. key = '/commissaire/clusters/{0}'.format(name) try: etcd_resp = self.store.get(key) self.logger.info( 'Creation of already exisiting cluster {0} requested.'.format( name)) except etcd.EtcdKeyNotFound: 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)) cluster = Cluster(**json.loads(etcd_resp.value)) 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(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_delete(self, req, resp, address): """ Handles the Deletion of a 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 """ resp.body = "{}" try: host = self.store.delete("/commissaire/hosts/{0}".format(address)) resp.status = falcon.HTTP_410 except etcd.EtcdKeyNotFound: resp.status = falcon.HTTP_404 # Also remove the host from all clusters. # Note: We've done all we need to for the host deletion, # so if an error occurs from here just log it and # return. try: clusters_dir = self.store.get("/commissaire/clusters") except etcd.EtcdKeyNotFound: self.logger.warn("Etcd does not have any clusters") return if len(clusters_dir._children): for etcd_resp in clusters_dir.leaves: cluster = Cluster(**json.loads(etcd_resp.value)) if address in cluster.hostset: cluster.hostset.remove(address) self.store.set(etcd_resp.key, cluster.to_json(secure=True))
def on_delete(self, req, resp, address): """ Handles the Deletion of a 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 """ resp.body = '{}' try: self.store.delete(util.etcd_host_key(address)) resp.status = falcon.HTTP_200 except etcd.EtcdKeyNotFound: resp.status = falcon.HTTP_404 # Also remove the host from all clusters. # Note: We've done all we need to for the host deletion, # so if an error occurs from here just log it and # return. try: clusters_dir = self.store.get('/commissaire/clusters') self.logger.debug('Etcd Response: {0}'.format(clusters_dir)) except etcd.EtcdKeyNotFound: self.logger.warn('Etcd does not have any clusters') return if len(clusters_dir._children): self.logger.info( 'There are clusters associated with {0}...'.format(address)) for etcd_resp in clusters_dir.leaves: cluster = Cluster(**json.loads(etcd_resp.value)) if address in cluster.hostset: cluster_name = etcd_resp.key.split('/')[-1] self.logger.info('Removing {0} from cluster {1}'.format( address, cluster_name)) cluster.hostset.remove(address) self.store.set(etcd_resp.key, cluster.to_json(secure=True)) self.logger.info( '{0} has been removed from cluster {1}'.format( address, cluster_name))
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 """ # TODO: Verify input try: host = self.store.get("/commissaire/hosts/{0}".format(address)) resp.status = falcon.HTTP_409 return except etcd.EtcdKeyNotFound: pass data = req.stream.read().decode() host_creation = json.loads(data) ssh_priv_key = host_creation["ssh_priv_key"] host_creation["address"] = address host_creation["os"] = "" host_creation["status"] = "investigating" host_creation["cpus"] = -1 host_creation["memory"] = -1 host_creation["space"] = -1 host_creation["last_check"] = None # Don't store the cluster name in etcd. cluster_name = host_creation.pop("cluster", None) # Verify the cluster exists, if given. Do it now # so we can fail before writing anything to etcd. if cluster_name: # XXX: Based on ClusterSingleHostResource.on_put(). # Add a util module to share common operations. cluster_key = "/commissaire/clusters/{0}".format(cluster_name) try: etcd_resp = self.store.get(cluster_key) self.logger.info("Request for cluster {0}".format(cluster_name)) self.logger.debug("{0}".format(etcd_resp)) except etcd.EtcdKeyNotFound: self.logger.info("Request for non-existent cluster {0}.".format(cluster_name)) resp.status = falcon.HTTP_409 return cluster = Cluster(**json.loads(etcd_resp.value)) hostset = set(cluster.hostset) hostset.add(address) # Ensures no duplicates cluster.hostset = list(hostset) host = Host(**host_creation) new_host = self.store.set("/commissaire/hosts/{0}".format(address), host.to_json(secure=True)) INVESTIGATE_QUEUE.put((host_creation, ssh_priv_key)) # Add host to the requested cluster. if cluster_name: # FIXME: Should guard against races here, since we're fetching # the cluster record and writing it back with some parts # unmodified. Use either locking or a conditional write # with the etcd 'modifiedIndex'. Deferring for now. self.store.set(cluster_key, cluster.to_json(secure=True)) resp.status = falcon.HTTP_201 req.context["model"] = Host(**json.loads(new_host.value))