def install_config(ctx=None, output_path=None, **kwargs): """Install config file. Agrs: ctx (object): Click Context object. output_path (path): Path to place conf file. """ if not ctx: # Using API. Else handled by cli. _set_init_vars(kwargs.get("cwd"), kwargs.get("tmpdir")) if not output_path: output_path = get_env_var("cwd") path = os.path.join(output_path, "%s.conf" % PROJECT_NAME) if os.path.exists(path): utils.abort("%s.conf already esists." % PROJECT_NAME) else: with open(path, "w") as f: f.write("""\ [up] provider = virtualbox box = ubuntu/bionic64 sync_dirs = [["saltstack/etc", "/etc/salt"], ["saltstack/srv", "/srv"]] """) utils.echo("Created config at %s" % path)
def install_gitignore(ctx=None, output_path=None, **kwargs): """Install config file. Agrs: ctx (object): Click Context object. output_path (path): Path to place conf file. """ if not ctx: # Using API. Else handled by cli. _set_init_vars(kwargs.get("cwd"), kwargs.get("tmpdir")) if not output_path: output_path = get_env_var("cwd") path = os.path.join(output_path, ".gitignore") if os.path.exists(path): pass else: with open(path, "w") as f: f.write("""\ .rambo-tmp/ .vagrant/ my_rambo.conf auth/ """) utils.echo("Created .gitignore")
def createproject(project_name, cwd, tmpdir, config_only=None, ctx=None): """Create project with basic configuration files. Agrs: project_name (path): Place to create a new project. Must be non-existing dir. config_only (bool): Determins if we should only place a conf file in the new project. """ # initialize paths _set_env() cwd = _set_cwd(cwd) path = os.path.join(cwd, project_name) _set_tmpdir(path) # create new project dir try: os.makedirs(path) # Make parent dirs if needed. except FileExistsError: utils.abort("Directory already exists.") utils.echo('Created %s project "%s" in %s.' % (PROJECT_NAME.capitalize(), project_name, path)) # Fill project dir with basic configs. install_config(ctx, output_path=path) install_gitignore(ctx, output_path=path) if not config_only: export("saltstack", path) install_auth(ctx, output_path=path)
def export(resource=None, export_path=None, force=None): """Drop default code in the CWD / user defined space. Operate on saltstack and vagrant resources. Agrs: resource (str): Resource to export: saltstack or vagrant. export_path (path): Dir to export resources to. force (bool): Determins if we should overwrite and merge conflicting files in the target path. """ if export_path: output_dir = os.path.normpath(export_path) else: output_dir = os.getcwd() if resource in ("vagrant", "saltstack"): srcs = [os.path.normpath(os.path.join(PROJECT_LOCATION, resource))] dsts = [os.path.join(output_dir, resource)] if resource == "vagrant": srcs.append( os.path.normpath(os.path.join(PROJECT_LOCATION, "settings.json"))) srcs.append( os.path.normpath(os.path.join(PROJECT_LOCATION, "Vagrantfile"))) dsts.append(os.path.join(output_dir, "settings.json")) dsts.append(os.path.join(output_dir, "Vagrantfile")) if not force: try: for path in dsts: if os.path.exists(path): click.confirm( "One or more destination files or directories in " "'%s' already exists. Attempt to merge and " "overwrite?" % dsts, abort=True, ) break # We only need general confirmation of an overwrite once. except UnboundLocalError: # dsts referenced before assignement utils.abort("The resource '%s' is not a valid option." % resource) for src, dst in zip(srcs, dsts): try: copy_tree(src, dst) # Merge copy tree with overwrites. except DistutilsFileError: # It's a file, not a dir. try: shutil.copy(src, dst) # Copy file with overwrites. except FileNotFoundError: os.makedirs( os.path.dirname(dst), exist_ok=True) # Make parent dirs if needed. # Py 3.2+ shutil.copy(src, dst) # Copy file with overwrites. utils.echo("Done exporting %s code." % resource)
def _invoke_vagrant(cmd=None): """Pass a command to vagrant. This outputs in near real-time, logs both stderr and stdout in a combined file, and detects stderr for our own error handling. Returns returncode (exitcode) of the command. Args: cmd (str): The cmd string that is appended to `vagrant ...`, passed to the shell and executed. """ masters, slaves = zip(pty.openpty(), pty.openpty()) cmd = " ".join(["vagrant", cmd]).split() with Popen(cmd, stdin=slaves[0], stdout=slaves[0], stderr=slaves[1]) as p: for fd in slaves: os.close(fd) # no input readable = { masters[0]: sys.stdout.buffer, # store buffers seperately masters[1]: sys.stderr.buffer, } while readable: for fd in select(readable, [], [])[0]: try: data = os.read(fd, 1024) # read available except OSError as e: if e.errno != errno.EIO: raise # XXX cleanup del readable[fd] # EIO means EOF on some systems else: if not data: # EOF del readable[fd] else: if fd == masters[0]: # We caught stdout utils.echo(data.rstrip()) utils.write_to_log(data) else: # We caught stderr utils.echo(data.rstrip(), err=True) utils.write_to_log(data, "stderr") readable[fd].flush() for fd in masters: os.close(fd) return p.returncode
def install_auth(ctx=None, output_path=None, **kwargs): """Install auth directory. Agrs: ctx (object): Click Context object. output_path (path): Path to place auth dir. """ if not ctx: # Using API. Else handled by cli. _set_init_vars(kwargs.get("cwd"), kwargs.get("tmpdir")) if not output_path: output_path = get_env_var("cwd") license_dir = os.path.join(output_path, "auth/licenses") try: os.makedirs(license_dir) except FileExistsError: pass # Dir already created. Moving on. utils.echo( "Any (license) files you put in %s will be synced into your VM." % license_dir) for filename in os.listdir( os.path.join(get_env_var("env"), "auth/env_scripts")): dst_dir = os.path.join(output_path, "auth/keys") dst = os.path.join(dst_dir, os.path.splitext(filename)[0]) if not os.path.isfile(dst): os.makedirs(dst_dir, exist_ok=True) # Make parent dirs if needed. # Py 3.2+ shutil.copy( os.path.join(get_env_var("env"), "auth/env_scripts", filename), dst) utils.echo("Added template key loading scripts %s to auth/keys." % filename) else: utils.echo("File %s exists. Leaving it." % dst)
def install_plugins(force=None, plugins=("all", )): """Install all of the vagrant plugins needed for all plugins Agrs: force (bool): Forces bypassing of reinstallation prompt. plugins (tuple): Names of vagrant plugins to install. """ host_system = platform.system() for plugin in plugins: if plugin == "all": utils.echo("Installing all default plugins.") for plugin in SETTINGS["PLUGINS"][host_system]: _invoke_vagrant("plugin install %s" % plugin) elif plugin in SETTINGS["PLUGINS"][host_system]: _invoke_vagrant("plugin install %s" % plugin) else: if not force: click.confirm( 'The plugin "%s" is not in our list of plugins. Attempt ' "to install anyway?" % plugin, abort=True, ) vagrant_general_command("plugin install %s" % plugin)
def destroy(ctx=None, **params): """Destroy a VM / container and all its metadata. Default leaves logs. All str args can also be set as an environment variable; arg takes precedence. Agrs: ctx (object): Click Context object. vagrant_cwd (path): Location of `Vagrantfile`. Used if invoked with API only. vagrant_dotfile_path (path): Location of `.vagrant` metadata directory. Used if invoked with API only. """ # TODO add finding and deleting of all VMs registered to this installation. # TODO (optional) add finding and deleting of all VMs across all installations. # TODO add an --all flag to delete the whole .rambo-tmp dir. Default leaves logs. if not ctx: # Using API. Else handled by cli. _set_init_vars(params.get("cwd"), params.get("tmpdir")) _set_vagrant_vars(params.get("vagrant_cwd"), params.get("vagrant_dotfile_path")) destroy_cmd = vagrant_general_command("destroy --force") # If there's any error code from Vagrant, don't delete the metadata. if not destroy_cmd: # I.e. we succeeded - ret code == 0 utils.file_delete(os.path.join(get_env_var("TMPDIR"), "provider")) utils.file_delete(os.path.join(get_env_var("TMPDIR"), "random_tag")) utils.dir_delete(os.environ.get("VAGRANT_DOTFILE_PATH")) utils.echo("Temporary files removed") if params.get("vm_name"): # Additionally remove the box if we can. utils.echo( f"Now removing base VirtualBox data for VM {params['vm_name']}." ) os.system(f"vboxmanage controlvm {params['vm_name']} poweroff") os.system(f"vboxmanage unregistervm {params['vm_name']} --delete") utils.echo("Destroy complete.") else: utils.echo("We received an error. Destroy may not be complete.")