def addWorker(self, args): """ Adds the given worker to the deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if args.size: size = args.size if args.memory: raise InputErrorException('AmbiguousSize') elif args.memory: memory = args.memory size = self._get_size_from_memory(memory) else: size = None if not deployment_name: raise InputErrorException('NoDeployment') if not args.command: raise InputErrorException('NoWorkerCommandGiven') try: self.api.create_worker( app_name, deployment_name, args.command, params=args.params, size=size) except BadRequestError as e: if 'size' in e.msgs: if args.memory: raise InputErrorException('InvalidMemory') if args.size: raise InputErrorException('InvalidSize') else: raise return True
def showAddonCreds(self, args): """ Print the creds.json of all Add-ons """ app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.addon: try: addons = self.api.read_addons(app_name, deployment_name) except: raise else: print_addon_creds(addons) return True else: try: addon = self.api.read_addon( app_name, deployment_name, args.addon) except GoneError: raise InputErrorException('WrongAddon') else: print_addon_creds([addon]) return True
def removeUser(self, args): """ Remove a user specified by the user name or email address from an application. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) # @UnusedVariable if '@' in args.username: if deployment_name: users = self.api.read_deployment_users(app_name, deployment_name) else: users = self.api.read_app(app_name)['users'] try: username = [user['username'] for user in users if user['email'] == args.username][0] except IndexError: raise InputErrorException('RemoveUserGoneError') else: username = args.username try: if deployment_name: self.api.delete_deployment_user(app_name, deployment_name, username) else: self.api.delete_app_user(app_name, username) except GoneError: raise InputErrorException('RemoveUserGoneError') return True
def undeploy(self, args): """ Undeploys the deployment, deletes the database and files. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not self.does_app_exist(app_name): raise InputErrorException('WrongApplication') if not args.force_delete: question = raw_input('Do you really want to delete this ' + 'deployment? This will delete everything including files ' + 'and the database. Type "Yes" without the quotes to delete: ') else: question = 'Yes' if question.lower() == 'yes': args.force_delete = True try: self.api.delete_deployment(app_name, deployment_name) except GoneError: raise InputErrorException('WrongDeployment') else: print messages['SecurityQuestionDenied'] return True
def showAddon(self, args): """ Shows the details of an addon. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.addon: try: addons = self.api.read_addons(app_name, deployment_name) except: raise else: print_addon_list(addons) return True else: try: addon = self.api.read_addon( app_name, deployment_name, args.addon) except GoneError: raise InputErrorException('WrongAddon') else: print_addon_details(addon) return True
def addAlias(self, args): """ Adds the given alias to the deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.alias: raise InputErrorException('NoAliasGiven') self.api.create_alias(app_name, args.alias, deployment_name) return True
def activate(self, args): """ Activate a new user using the information from the activation email. """ self.api.set_token(None) try: self.api.update_user(args.user_name[0], activation_code=args.activation_code[0]) except GoneError: raise InputErrorException('WrongUsername') except NotImplementedError: raise InputErrorException('CommandNotImplemented')
def removeCron(self, args): """ Removes an worker form a deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') try: self.api.delete_cronjob(app_name, deployment_name, args.job_id) except GoneError: raise InputErrorException('NoSuchCronJob') return True
def _get_size_from_memory(self, memory): res = re.match(r'(\d+)(.*)', memory.lower()) if not res: raise InputErrorException('InvalidMemory') if res.group(2) in ['mb', 'm', '']: size = float(res.group(1)) / 128 elif res.group(2) in ['gb', 'g']: size = float(res.group(1)) * 2 ** 10 / 128 else: raise InputErrorException('InvalidMemory') final_size = int(math.ceil(size)) if final_size != size: print >> sys.stderr, 'Memory size has to be a multiple of 128MB and has been rounded up to {0}MB.'.format(final_size * 128) return final_size
def addCron(self, args): """ Adds the given worker to the deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.url: raise InputErrorException('NoCronURLGiven') self.api.create_cronjob( app_name, deployment_name, args.url) return True
def updateAddon(self, args): #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') try: self.api.update_addon( app_name, deployment_name, args.addon_old, args.addon_new) except GoneError: raise InputErrorException('WrongAddon') else: return True
def removeAddon(self, args): """ Removes an addon form a deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.addon: raise InputErrorException('NoAddonGiven') try: self.api.delete_addon(app_name, deployment_name, args.addon) except GoneError: raise InputErrorException('WrongAddon') return True
def setup(self, args): user_config = get_user_config(self.settings) ssh_key_path = self._get_setup_ssh_key_path(user_config, args) if not is_key_valid(ssh_key_path): # If given key path is not default and does not exist # we raise an error if ssh_key_path != get_default_ssh_key_path(): raise InputErrorException('WrongPublicKey') # If given key path was the default one, we create the key # pair for the user print >> sys.stderr, "Key '{0}' seems to not be a RSA public key or not found!".format( ssh_key_path) create_new_default_ssh_keys() ssh_key_content = readContentOf(ssh_key_path) ssh_auth = self._get_setup_ssh_auth(self.settings, user_config, args) if args.email: set_user_config(self.settings, email=args.email) try: users = self.api.read_users() self.api.create_user_key(users[0]['username'], ssh_key_content) except ConflictDuplicateError: # Key already added, nothing to do. pass set_user_config(self.settings, ssh_auth=ssh_auth, ssh_path=ssh_key_path)
def create(self, args): """ Create a new user. """ if not self.settings.user_registration_enabled: print messages['RegisterDisabled'].format( self.settings.user_registration_url) return self.api.set_token(None) if args.name and args.email and args.password: name = args.name[0] email = args.email[0] password = args.password[0] else: name = raw_input('Username: '******'CommandNotImplemented') print messages['UserCreatedNowCheckEmail']
def _details(self, app_or_deployment_name): app_name, deployment_name = self.parse_app_deployment_name(app_or_deployment_name) if deployment_name: try: deployment = self.api.read_deployment( app_name, deployment_name) try: app_users = self.api.read_app_users(app_name) except (UnauthorizedError, ForbiddenError, NotImplementedError): # ok since possibly I am not allowed to see users at all pass else: deployment['users'] = [ dict(au, app=True) for au in app_users ] + deployment['users'] except GoneError: raise InputErrorException('WrongDeployment') else: return app_name, deployment_name, deployment else: try: app = self.api.read_app(app_name) # only get deployment-users if i can see app-users if len(app['users']): try: for deployment in app['deployments']: appname, depname = self.parse_app_deployment_name(deployment['name']) depusers = self.api.read_deployment_users(appname, depname) app['users'].extend( dict(du, deployment=depname) for du in depusers ) except (NotImplementedError, BadRequestError): # for old api-servers pass except GoneError: raise InputErrorException('WrongApplication') else: return app_name, deployment_name, app
def readContentOf(filename): """ Read a given file's content into a string Returns contents of given file as string, otherwise "None" """ file_content = '' if not os.path.isfile(os.path.abspath(filename)): raise InputErrorException('FileNotFound') try: open_file = open(os.path.abspath(filename), 'r') file_content = str(open_file.read()) except IOError: raise InputErrorException('FileReadOrWriteFailed') return file_content.strip()
def addAddon(self, args): """ Adds the given addon to the deployment. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.addon: raise InputErrorException('NoAddonGiven') options = None if args.options: options = parse_additional_addon_options(args.options) try: self.api.create_addon(app_name, deployment_name, args.addon, options) except ConflictDuplicateError: raise InputErrorException('DuplicateAddon') return True
def log(self, args): """ Show the log. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') last_time = None while True: #noinspection PyUnusedLocal logEntries = [] try: logEntries = self.api.read_log( app_name, deployment_name, args.type, last_time=last_time) except GoneError: raise InputErrorException('WrongApplication') if len(logEntries) > 0: last_time = datetime.fromtimestamp(float(logEntries[-1]["time"])) if args.type == 'worker' and args.wrk_id: logEntries = filter(lambda entry: entry['wrk_id'] == args.wrk_id, logEntries) if args.filter: if args.type in ["error", "worker"]: logEntries = filter( lambda entry: re.search( re.compile(args.filter, re.IGNORECASE), entry['message']), logEntries) if args.type == 'access': logEntries = filter(lambda entry: re.search( re.compile(args.filter, re.IGNORECASE), entry['first_request_line'] + entry['referer'] + entry['user_agent'] + entry['remote_host']), logEntries) print_log_entries(logEntries, args.type) time.sleep(2)
def extract_flag_from_variables(variables, flag_names, flag_value): flag_found = False for flag_name in flag_names: if flag_name in variables: variables.remove(flag_name) flag_found = True if flag_value and flag_found: raise InputErrorException('DuplicatedFlag') return variables, flag_value or flag_found
def delete(self, args): """ Delete your user account. """ apps = self.api.read_apps() if len(apps) > 0: raise InputErrorException('DeleteAppsBeforeUser') users = self.api.read_users() if not args.force_delete: question = raw_input('Do you really want to delete your user? ' + 'Type "Yes" without the quotes to delete: ') else: question = 'Yes' if question.lower() == 'yes': self.api.delete_user(users[0]['username']) # After we have deleted our user we should also delete # the token_file to avoid confusion self.api.set_token(None) else: raise InputErrorException('SecurityQuestionDenied')
def deploy(self, args): """ Deploy a distinct version. Since we want to make it as easy as possible we first try to update the default deployment and start the newest version of that if no other arguments were passed at the command line. """ try: #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) except ParseAppDeploymentName: raise InputErrorException('InvalidApplicationName') if args.size: size = args.size if args.memory: raise InputErrorException('AmbiguousSize') elif args.memory: memory = args.memory size = self._get_size_from_memory(memory) else: size = None try: try: self.api.update_deployment( app_name, version=args.version, deployment_name=deployment_name, min_boxes=args.containers, max_boxes=size, stack=args.stack) except GoneError: try: self.api.create_deployment( app_name, deployment_name=deployment_name, stack=args.stack) self.api.update_deployment( app_name, version=args.version, deployment_name=deployment_name, min_boxes=args.containers, max_boxes=size, stack=args.stack) except GoneError: raise InputErrorException('WrongApplication') except ForbiddenError: raise InputErrorException('NotAllowed') except BadRequestError as e: if 'max_boxes_over_max_process_limit' in e.msgs: if args.memory: raise InputErrorException('InvalidMemory') if args.size: raise InputErrorException('InvalidSize') else: raise else: return True
def _open(self, app_or_deployment_name): app_name, deployment_name = self.parse_app_deployment_name(app_or_deployment_name) if not deployment_name: deployment_name = 'default' try: deployment = self.api.read_deployment( app_name, deployment_name) except GoneError: raise InputErrorException('WrongDeployment') else: return app_name, deployment_name, deployment
def showAlias(self, args): """ Shows the details of an alias. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.alias: aliases = self.api.read_aliases(app_name, deployment_name) print_alias_list(aliases) return True else: try: alias = self.api.read_alias( app_name, args.alias, deployment_name) except GoneError: raise InputErrorException('WrongAlias') else: print_alias_details(alias) return True
def showWorker(self, args): """ Shows the details of an worker. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.wrk_id: workers = (self.api.read_worker(app_name, deployment_name, worker['wrk_id']) for worker in self.api.read_workers(app_name, deployment_name)) print_worker_list(workers) return True else: try: worker = self.api.read_worker( app_name, deployment_name, args.wrk_id) except GoneError: raise InputErrorException('WrongWorker') else: print_worker_details(worker) return True
def showCron(self, args): """ Shows the details of an worker. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not deployment_name: raise InputErrorException('NoDeployment') if not args.job_id: cronjobs = self.api.read_cronjobs(app_name, deployment_name) print_cronjob_list(cronjobs) return True else: try: cronjob = self.api.read_cronjob( app_name, deployment_name, args.job_id) except GoneError: raise InputErrorException('NoSuchCronJob') else: print_cronjob_details(cronjob) return True
def delete(self, args): """ Delete an application. If we wouldn't check the token here it could happen that we ask the user for confirmation and then fire the api request. If the token wasn't valid this would result in a TokenRequiredError being raised and after getting the credentials and creating a token this method would be called a second time. This would result in asking the user two times if he really wants to delete the app which is a rather bad user experience. """ if self.api.check_token(): #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) if not self.does_app_exist(app_name): raise InputErrorException('WrongApplication') if deployment_name: raise InputErrorException('DeleteOnlyApplication') if not args.force_delete: question = raw_input('Do you really want to delete this ' + 'application? Type "Yes" without the quotes to delete: ') else: question = 'Yes' if question.lower() == 'yes': try: self.api.delete_app(app_name) except ForbiddenError: raise InputErrorException('NotAllowed') except BadRequestError: raise InputErrorException('CannotDeleteDeploymentExist') except GoneError: raise InputErrorException('WrongApplication') else: print messages['SecurityQuestionDenied'] else: raise TokenRequiredError
def run_cmd(self, args): try: app_name, deployment_name = self.parse_app_deployment_name(args.name) except ParseAppDeploymentName: raise InputErrorException('InvalidApplicationName') if deployment_name == '': raise InputErrorException('NoDeployment') user_host = '{app}-{dep}@{host}'.format(app=app_name, dep=deployment_name, host=SSH_FORWARDER) # Refresh our token before sending it to the forwarder. try: self.api.read_deployment(app_name, deployment_name) except GoneError: raise InputErrorException('WrongApplication') env = 'TOKEN={token}'.format(token=self.api.get_token()['token']) if len(args.command) > 0: command = '{env} {command}'.format(env=env, command=args.command) else: raise InputErrorException('NoRunCommandGiven') sshopts = shlex.split(os.environ.get('CCTRL_SSHOPTS', '')) ssh_cmd = ['ssh', '-t'] + sshopts + ['-p', SSH_FORWARDER_PORT, '--', user_host, command] subprocess.call(ssh_cmd)
def removeKey(self, args): """ Remove one of your public keys specified by key_id. listKeys() shows the key_ids. """ users = self.api.read_users() if not args.force_delete: question = raw_input('Do you really want to remove your key? ' + 'Type "Yes" without the quotes to remove: ') else: question = 'Yes' if question.lower() == 'yes': self.api.delete_user_key(users[0]['username'], args.id[0]) else: raise InputErrorException('SecurityQuestionDenied')
def addUser(self, args): """ Add a user specified by the e-mail address to an application. """ #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) # @UnusedVariable try: if deployment_name: self.api.create_deployment_user(app_name, deployment_name, args.email, args.role) else: self.api.create_app_user(app_name, args.email, args.role) except ConflictDuplicateError: raise InputErrorException('UserBelongsToApp') return True
def create(self, args): """ Creates a new application. """ try: #noinspection PyTupleAssignmentBalance app_name, deployment_name = self.parse_app_deployment_name(args.name) except ParseAppDeploymentName: raise InputErrorException('InvalidApplicationName') if args.buildpack: # Did the user choose a default app type and provided a buildpack url? if not args.type == 'custom': raise InputErrorException('NoCustomApp') # Did the user provide a valid buildpack URL? elif not is_buildpack_url_valid(args.buildpack): raise InputErrorException('NoValidBuildpackURL') # Did the user provide a buildpack url if app has a custom type? elif args.type == 'custom': raise InputErrorException('NoBuildpackURL') # Did the user provide the repo type as argument? if args.repo: repo_type = args.repo detection_method = None else: # No, he/she didn't! Then check if current directory is an app and already has a CVS type ... (repo_type, detection_method) = CVSType.by_path(os.getcwd()) if repo_type is None: # Hmm, current directory was nothing. Let's check if either 'bzr' or 'git' is installed ... (repo_type, detection_method) = CVSType.by_env() if repo_type is None: # Hmm, also nothing installed! Ok, we give up and set default = GIT and hope for better times ... detection_method = 'CreatingAppAsDefaultRepoType' repo_type = CVSType.GIT try: self.api.create_app(app_name, args.type, repo_type, args.buildpack) self.api.create_deployment( app_name, deployment_name=deployment_name) if detection_method: print messages[detection_method] except GoneError: raise InputErrorException('WrongApplication') except ForbiddenError: raise InputErrorException('NotAllowed') else: return True