require "optparse" require "vagrant" # rubocop:disable Metrics/ClassLength module VagrantPlugins module Orchestrate module Command class Init < Vagrant.plugin("2", :command) include Vagrant::Util DEFAULT_SHELL_PATH = "{{YOUR_SCRIPT_PATH}}" DEFAULT_WINRM_USERNAME = "{{YOUR_WINRM_USERNAME}}" DEFAULT_WINRM_PASSWORD = "{{YOUR_WINRM_PASSWORD}}" DEFAULT_SSH_USERNAME = "{{YOUR_SSH_USERNAME}}" DEFAULT_SSH_PRIVATE_KEY_PATH = "{{YOUR_SSH_PRIVATE_KEY_PATH}}" DEFAULT_PLUGINS = ["vagrant-orchestrate", "vagrant-managed-servers"] # rubocop:disable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def execute options = {} options[:provisioners] = [] options[:servers] = [] options[:environments] = [] options[:plugins] = DEFAULT_PLUGINS options[:puppet_librarian_puppet] = false options[:puppet_hiera] = true options[:git] = true opts = OptionParser.new do |o| o.banner = "Usage: vagrant orchestrate init [options]" o.separator "" o.separator "Options:" o.separator "" o.on("--provision-with x,y,z", Array, "Init only certain provisioners, by type.") do |list| options[:provisioners] = list end o.on("--shell", "Shorthand for --provision-with shell") do options[:provisioners] << "shell" end o.on("--shell-paths x,y,z", Array, "Comma-separated list of shell scripts to run on provision. Only with --shell") do |list| options[:shell_paths] = list end o.on("--shell-inline command", String, "Inline script to run. Only with --shell") do |c| options[:shell_inline] = c end o.on("--puppet", "Shorthand for '--provision-with puppet'") do options[:provisioners] << "puppet" end o.on("--[no-]puppet-hiera", "Include templates for hiera. Only with --puppet") do |p| options[:puppet_hiera] = p end o.on("--[no-]puppet-librarian-puppet", "Include a Puppetfile and the vagrant-librarian-puppet plugin. Only with --puppet") do |p| options[:puppet_librarian_puppet] = p end o.on("--ssh-username USERNAME", String, "The username for communicating over ssh") do |u| options[:ssh_username] = u end o.on("--ssh-password PASSWORD", String, "The password for communicating over ssh") do |p| options[:ssh_password] = p end o.on("--ssh-private-key-path PATH", String, "Paths to the private key for communinicating over ssh") do |k| options[:ssh_private_key_path] = k end o.on("--winrm", "Use the winrm communicator") do options[:communicator] = "winrm" options[:plugins] << "vagrant-winrm-s" end o.on("--winrm-username USERNAME", String, "The username for communicating with winrm") do |u| options[:winrm_username] = u end o.on("--winrm-password PASSWORD", String, "The password for communicating with winrm") do |p| options[:winrm_password] = p end o.on("--plugins x,y,z", Array, "A comma separated list of vagrant plugins to be installed") do |p| options[:plugins] += p end o.on("--servers x,y,z", Array, "A CSV list of FQDNs to target managed servers") do |list| options[:servers] = list end o.on("--environments x,y,z", Array, "A CSV list of environments. Takes precedence over --servers") do |list| options[:environments] = list end o.on("--[no-]git", "Include useful templates for working in a git repository. Default is true.") o.on("-f", "--force", "Force overwriting of files") do options[:force] = true end o.on("--credentials-prompt", "Prompt for credentials when performing orchestrate operations") do options[:creds_prompt] = true end cfpmsg = "The path to a yaml file containing :username and :password fields to use with vagrant orchestrate" o.on("--credentials-file-path FILEPATH", String, cfpmsg) do |file_path| options[:creds_file_path] = file_path end end argv = parse_options(opts) return unless argv options[:shell_paths] ||= options[:shell_inline] ? [] : [DEFAULT_SHELL_PATH] options[:winrm_username] ||= DEFAULT_WINRM_USERNAME options[:winrm_password] ||= DEFAULT_WINRM_PASSWORD options[:communicator] ||= "ssh" options[:ssh_username] ||= DEFAULT_SSH_USERNAME options[:ssh_private_key_path] ||= DEFAULT_SSH_PRIVATE_KEY_PATH unless options[:ssh_password] init_puppet options init_environments options init_vagrant_files options init_git options @env.ui.info(I18n.t("vagrant.commands.init.success"), prefix: false) # Success, exit status 0 0 end # rubocop:enable Metrics/AbcSize, MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity private def init_puppet(options) return unless options[:provisioners].include? "puppet" FileUtils.mkdir_p(File.join(@env.cwd, "puppet")) if options[:puppet_librarian_puppet] contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/puppet/Puppetfile")) write_file File.join("puppet", "Puppetfile"), contents, options FileUtils.mkdir_p(File.join(@env.cwd, "puppet", "modules")) write_file(File.join(@env.cwd, "puppet", "modules", ".gitignore"), "*", options) if options[:git] options[:plugins] << "vagrant-librarian-puppet" end if options[:puppet_hiera] contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/puppet/hiera.yaml")) write_file(File.join("puppet", "hiera.yaml"), contents, options) FileUtils.mkdir_p(File.join(@env.cwd, "puppet", "hieradata")) contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/puppet/hiera/common.yaml")) write_file(File.join(@env.cwd, "puppet", "hieradata", "common.yaml"), contents, options) end FileUtils.mkdir_p(File.join(@env.cwd, "puppet", "manifests")) write_file(File.join(@env.cwd, "puppet", "manifests", "default.pp"), "# Your puppet code goes here", options) end def init_environments(options) environments = options[:environments] return unless environments.any? contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/environment/servers.json"), environments: environments) write_file("servers.json", contents, options) @env.ui.info("You've created an environment-aware configuration.") @env.ui.info("To complete the process, you need to do the following: ") @env.ui.info(" 1. Add the target servers to servers.json") @env.ui.info(" 2. Commit your changes") @env.ui.info(" 3. Create a git branch for each environment") environments.each do |env| @env.ui.info(" git branch #{env}") end end def init_vagrant_files(options) contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/vagrant/Vagrantfile"), provisioners: options[:provisioners], shell_paths: options[:shell_paths], shell_inline: options[:shell_inline], puppet_librarian_puppet: options[:puppet_librarian_puppet], puppet_hiera: options[:puppet_hiera], communicator: options[:communicator], winrm_username: options[:winrm_username], winrm_password: options[:winrm_password], ssh_username: options[:ssh_username], ssh_password: options[:ssh_password], ssh_private_key_path: options[:ssh_private_key_path], servers: options[:servers], environments: options[:environments], creds_prompt: options[:creds_prompt] ) write_file("Vagrantfile", contents, options) contents = TemplateRenderer.render(Orchestrate.source_root.join("templates/vagrant/.vagrantplugins"), plugins: options[:plugins] ) write_file(".vagrantplugins", contents, options) FileUtils.cp(Orchestrate.source_root.join("templates", "vagrant", "dummy.box"), File.join(@env.cwd, "dummy.box")) end def init_git(options) return unless options[:git] gitignore_path = File.join(@env.cwd, ".gitignore") contents = ::IO.readlines(gitignore_path) if File.exist?(gitignore_path) contents ||= [] open(gitignore_path, "a") do |f| %w( .vagrant/ ).each do |path| f.puts path unless contents.include?(path + "\n") end end end def write_file(filename, contents, options) save_path = Pathname.new(filename).expand_path(@env.cwd) save_path.delete if save_path.exist? && options[:force] fail Vagrant::Errors::VagrantfileExistsError if save_path.exist? begin save_path.open("w+") do |f| f.write(contents) end rescue Errno::EACCES raise Vagrant::Errors::VagrantfileWriteError end end end end end end # rubocop:enable Metrics/ClassLength