├── test ├── test_data │ ├── kubectl │ ├── docker-1.11.0.tgz │ ├── docker-1.9.1.zip │ ├── docker-1.10.0.tar.gz │ ├── openshift-origin-client-tools-v1.2.0-2e62fab-mac.zip │ ├── openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.zip │ └── openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.tar.gz ├── vagrant-service-manager │ ├── archive_handler_test.rb │ ├── service_base_test.rb │ ├── proxy_test.rb │ ├── installer_test.rb │ └── binary_handlers │ │ ├── adb_kubernetes_binary_handler_test.rb │ │ ├── adb_openshift_binary_handler_test.rb │ │ └── adb_docker_binary_handler_test.rb ├── fake_https_server.rb ├── fake_http_proxy.rb └── test_helper.rb ├── .gitattributes ├── .ci ├── ansible │ ├── roles │ │ └── centos │ │ │ ├── vars │ │ │ └── main.yml │ │ │ └── tasks │ │ │ └── main.yml │ └── site.yml └── jenkins-execute-script.py ├── lib ├── vagrant-service-manager │ ├── version.rb │ ├── binary_handlers │ │ ├── adb_binary_handler.rb │ │ ├── cdk_binary_handler.rb │ │ ├── cdk_docker_binary_handler.rb │ │ ├── cdk_kubernetes_binary_handler.rb │ │ ├── cdk_openshift_binary_handler.rb │ │ ├── adb_kubernetes_binary_handler.rb │ │ ├── adb_docker_binary_handler.rb │ │ ├── adb_openshift_binary_handler.rb │ │ └── binary_handler.rb │ ├── plugin_logger.rb │ ├── archive_handlers │ │ ├── zip_handler.rb │ │ └── tar_handler.rb │ ├── action │ │ └── setup_network.rb │ ├── service.rb │ ├── plugin.rb │ ├── config.rb │ ├── installer.rb │ ├── service_base.rb │ ├── services │ │ ├── kubernetes.rb │ │ ├── docker.rb │ │ └── openshift.rb │ ├── plugin_util.rb │ └── command.rb └── vagrant-service-manager.rb ├── Guardfile ├── .gitignore ├── plugins ├── hosts │ ├── linux │ │ ├── cap │ │ │ └── os_arch.rb │ │ └── plugin.rb │ ├── darwin │ │ ├── cap │ │ │ └── os_arch.rb │ │ └── plugin.rb │ └── windows │ │ ├── plugin.rb │ │ └── cap │ │ └── os_arch.rb └── guests │ └── redhat │ ├── cap │ ├── sha_id.rb │ ├── os_variant.rb │ ├── machine_ip.rb │ └── box_version.rb │ └── plugin.rb ├── .config └── cucumber.yml ├── .rubocop.yml ├── features ├── support │ ├── ci_formatter.rb │ └── env.rb ├── kubernetes.feature ├── help.feature ├── adb-openshift.feature ├── cdk-openshift.feature └── docker.feature ├── Gemfile ├── .github └── ISSUE_TEMPLATE.MD ├── vagrant-service-manager.gemspec ├── .rubocop_todo.yml ├── CONTRIBUTING.adoc ├── Rakefile ├── locales └── en.yml ├── commands.adoc ├── CHANGELOG.adoc └── README.adoc /test/test_data/kubectl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | CHANGELOG.md merge=union 2 | -------------------------------------------------------------------------------- /.ci/ansible/roles/centos/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/test_data/docker-1.11.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/docker-1.11.0.tgz -------------------------------------------------------------------------------- /test/test_data/docker-1.9.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/docker-1.9.1.zip -------------------------------------------------------------------------------- /lib/vagrant-service-manager/version.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | VERSION = '1.5.0'.freeze 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/test_data/docker-1.10.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/docker-1.10.0.tar.gz -------------------------------------------------------------------------------- /.ci/ansible/site.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | connection: local 3 | roles: 4 | - { role: centos, when: ansible_distribution == "CentOS" } 5 | -------------------------------------------------------------------------------- /test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-mac.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-mac.zip -------------------------------------------------------------------------------- /test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.zip -------------------------------------------------------------------------------- /test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectatomic/vagrant-service-manager/HEAD/test/test_data/openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.tar.gz -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | guard 'rake', task: 'html' do 5 | watch(/^.*.adoc/) 6 | end 7 | 8 | guard 'livereload' do 9 | watch(/^.*.html/) 10 | end 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ruby, Bundler 2 | Gemfile.lock 3 | .bundle 4 | .ruby-version 5 | .ruby-gemset 6 | 7 | # Vagrant 8 | .vagrant 9 | 10 | # Idea 11 | .idea 12 | *.iml 13 | 14 | # Build and tmp directories 15 | tmp 16 | build 17 | pkg 18 | .boxes 19 | -------------------------------------------------------------------------------- /plugins/hosts/linux/cap/os_arch.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module HostLinux 3 | module Cap 4 | class OSArch 5 | def self.os_arch(_env) 6 | `uname -m`.chop 7 | end 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /plugins/hosts/darwin/cap/os_arch.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module HostDarwin 3 | module Cap 4 | class OSArch 5 | def self.os_arch(_env) 6 | `uname -m`.chop 7 | end 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/adb_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class ADBBinaryHandler < BinaryHandler 4 | def initialize(machine, env, options) 5 | super(machine, env, options) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/cdk_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class CDKBinaryHandler < BinaryHandler 4 | def initialize(machine, env, options = {}) 5 | super(machine, env, options) 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /plugins/hosts/linux/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module HostLinux 5 | class Plugin < Vagrant.plugin('2') 6 | host_capability('linux', 'os_arch') do 7 | require_relative 'cap/os_arch' 8 | 9 | Cap::OSArch 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /plugins/hosts/darwin/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module HostDarwin 5 | class Plugin < Vagrant.plugin('2') 6 | host_capability('darwin', 'os_arch') do 7 | require_relative 'cap/os_arch' 8 | 9 | Cap::OSArch 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /plugins/hosts/windows/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module HostWindows 5 | class Plugin < Vagrant.plugin('2') 6 | host_capability('windows', 'os_arch') do 7 | require_relative 'cap/os_arch' 8 | 9 | Cap::OSArch 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /.config/cucumber.yml: -------------------------------------------------------------------------------- 1 | # config/cucumber.yml 2 | ##YAML Template 3 | --- 4 | default: --profile html --tags ~@ci-only --tags ~@todo 5 | ci: --format CiFormatter --no-color -m -b --tags ~@todo 6 | all: --profile html 7 | 8 | pretty: --format pretty -b 9 | html: --format progress --format html --out=build/features_report.html -b 10 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | AllCops: 4 | Exclude: 5 | - 'build/**/*' 6 | 7 | Metrics/LineLength: 8 | Max: 110 9 | Exclude: 10 | - 'Rakefile' 11 | 12 | Style/Documentation: 13 | Description: 'Document classes and non-namespace modules.' 14 | Enabled: false 15 | 16 | Style/FileName: 17 | Exclude: 18 | - 'lib/vagrant-service-manager.rb' 19 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/cdk_docker_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | # Currently client binary installation of docker for CDK is same as ADB 4 | class CDKDockerBinaryHandler < ADBDockerBinaryHandler 5 | def initialize(machine, env, options) 6 | super(machine, env, options) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/cdk_kubernetes_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | # Currently client binary installation of kubernetes for CDK is same as ADB 4 | class CDKKubernetesBinaryHandler < ADBKubernetesBinaryHandler 5 | def initialize(machine, env, options) 6 | super(machine, env, options) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /plugins/hosts/windows/cap/os_arch.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module HostWindows 3 | module Cap 4 | class OSArch 5 | def self.os_arch(_env) 6 | # Logic taken from http://stackoverflow.com/a/25845488 7 | arch = 'x86_64' 8 | 9 | if ENV['PROCESSOR_ARCHITECTURE'] == 'x86' 10 | arch = 'i386' unless ENV['PROCESSOR_ARCHITEW6432'] 11 | end 12 | 13 | arch 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/sha_id.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class ShaID 5 | def self.sha_id(machine, path) 6 | command = "sha256sum #{path}" 7 | 8 | return unless machine.communicate.test(command) # Return nil if command fails 9 | machine.communicate.execute(command) do |_, data| 10 | # sha256sum results in "sha_id path" 11 | return data.split.first 12 | end 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/os_variant.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class OsVariant 5 | def self.os_variant(machine) 6 | command = "grep VARIANT_ID #{OS_RELEASE_FILE}" 7 | # TODO: execute efficient command to solve this 8 | return unless machine.communicate.test(command) # Return nil if command fails 9 | machine.communicate.execute(command) do |_, data| 10 | return data.chomp.delete('"').split('=').last 11 | end 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/machine_ip.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class MachineIP 5 | def self.machine_ip(machine, options = {}) 6 | # Find the guest IP 7 | command = "ip -o -4 addr show up|egrep -v ': docker|: lo'|tail -1|awk '{print $4}'|cut -f1 -d\/" 8 | ip = '' 9 | 10 | PluginLogger.debug 11 | machine.communicate.execute(command) do |type, data| 12 | ip << data.chomp if type == :stdout 13 | return "IP=#{ip}" if options[:script_readable] 14 | end 15 | 16 | ip 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/cdk_openshift_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | # Currently client binary installation of openshift for CDK is same as ADB 4 | class CDKOpenshiftBinaryHandler < ADBOpenshiftBinaryHandler 5 | # Default to latest stable origin oc version for CDK as it is different than 6 | # OSE oc version running inside CDK development environment 7 | LATEST_OC_VERSION = '1.4.0'.freeze 8 | 9 | def initialize(machine, env, options) 10 | options['--cli-version'] = LATEST_OC_VERSION unless options['--cli-version'] 11 | super(machine, env, options) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/plugin_logger.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module PluginLogger 3 | @debug = false 4 | 5 | def self.debug_mode? 6 | @debug 7 | end 8 | 9 | def self.logger 10 | @logger 11 | end 12 | 13 | def self.enable_debug_mode 14 | @debug = true 15 | end 16 | 17 | def self.logger=(logger) 18 | @logger = logger 19 | end 20 | 21 | def self.command 22 | (ARGV.drop(1) - ['--debug', '--script-readable']).join(' ') 23 | end 24 | 25 | def self.debug(message = nil) 26 | return unless debug_mode? 27 | message = command.to_s if message.nil? 28 | logger.debug "[ service-manager: #{message} ]" 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /features/support/ci_formatter.rb: -------------------------------------------------------------------------------- 1 | require 'cucumber/formatter/pretty' 2 | 3 | class CiFormatter < Cucumber::Formatter::Pretty 4 | # A patch version of after_table_row which will also display the status in the table 5 | # See https://github.com/projectatomic/vagrant-service-manager/issues/419 6 | def after_table_row(table_row) 7 | return if !@table || @hide_this_step 8 | print_table_row_messages 9 | @io.print ' Result' if table_row.status.nil? 10 | @io.print " #{table_row.status.to_s.upcase}" unless table_row.status.nil? 11 | @io.puts 12 | return if !table_row.exception || @exceptions.include?(table_row.exception) 13 | print_exception(table_row.exception, table_row.status, @indent) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | group :development do 4 | gem 'vagrant', 5 | git: 'https://github.com/mitchellh/vagrant.git', 6 | ref: 'v1.8.4' 7 | gem 'mechanize' 8 | gem 'json' 9 | gem 'cucumber', '~> 2.1' 10 | gem 'aruba', '~> 0.13' 11 | gem 'komenda', '~> 0.1.6' 12 | gem 'launchy' 13 | gem 'rake', '10.4.2' 14 | gem 'rubocop', '0.44.1' 15 | gem 'guard-rake' 16 | gem 'guard-livereload', '~> 2.5', require: false 17 | gem 'asciidoctor' 18 | end 19 | 20 | group :test do 21 | gem 'minitest' 22 | gem 'mocha' 23 | end 24 | 25 | group :plugins do 26 | gemspec 27 | gem 'vagrant-libvirt' if RUBY_PLATFORM =~ /linux/i 28 | gem 'fog-libvirt', '0.0.3' if RUBY_PLATFORM =~ /linux/i # https://github.com/pradels/vagrant-libvirt/issues/568 29 | end 30 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/archive_handlers/zip_handler.rb: -------------------------------------------------------------------------------- 1 | require 'zip' 2 | 3 | module VagrantPlugins 4 | module ServiceManager 5 | class ZipHandler 6 | def initialize(source, dest_binary_path, file_regex) 7 | @source = source 8 | @dest_binary_path = dest_binary_path 9 | @file_regex = file_regex 10 | end 11 | 12 | def unpack 13 | Zip::File.open(@source) do |zipfile| 14 | zipfile.each do |entry| 15 | next unless entry.ftype == :file && entry.name =~ @file_regex 16 | 17 | dest_directory = File.dirname(@dest_binary_path) 18 | FileUtils.mkdir_p(dest_directory) unless File.directory?(dest_directory) 19 | zipfile.extract(entry, @dest_binary_path) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/archive_handlers/tar_handler.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems/package' 2 | require 'zlib' 3 | 4 | module VagrantPlugins 5 | module ServiceManager 6 | class TarHandler 7 | def initialize(source, dest_binary_path, file_regex) 8 | @source = source 9 | @dest_binary_path = dest_binary_path 10 | @file_regex = file_regex 11 | end 12 | 13 | def unpack 14 | Gem::Package::TarReader.new(Zlib::GzipReader.open(@source)) do |tar| 15 | tar.each do |entry| 16 | next unless entry.file? && entry.full_name =~ @file_regex 17 | 18 | dest_directory = File.dirname(@dest_binary_path) 19 | FileUtils.mkdir_p(dest_directory) unless File.directory?(dest_directory) 20 | File.open(@dest_binary_path, 'wb') { |f| f.print(entry.read) } 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /plugins/guests/redhat/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | require File.expand_path('../../../../', __FILE__) + '/lib/vagrant-service-manager/plugin_logger' 3 | 4 | module VagrantPlugins 5 | OS_RELEASE_FILE = '/etc/os-release'.freeze 6 | 7 | module GuestRedHat 8 | class Plugin < Vagrant.plugin('2') 9 | guest_capability('redhat', 'os_variant') do 10 | require_relative 'cap/os_variant' 11 | Cap::OsVariant 12 | end 13 | 14 | guest_capability('redhat', 'box_version') do 15 | require_relative 'cap/box_version' 16 | Cap::BoxVersion 17 | end 18 | 19 | guest_capability('redhat', 'sha_id') do 20 | require_relative 'cap/sha_id' 21 | Cap::ShaID 22 | end 23 | 24 | guest_capability('redhat', 'machine_ip') do 25 | require_relative 'cap/machine_ip' 26 | Cap::MachineIP 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.MD: -------------------------------------------------------------------------------- 1 | 8 | 9 | **OS details:** 10 | 11 | 12 | **Provider:** 13 | VirtualBox and/or Libvirt and/or HyperV (for CDK only) 14 | 15 | 16 | **Output of `vagrant -v`:** 17 | ``` 18 | (paste your output here) 19 | ``` 20 | 21 | **Output of `vagrant plugin list`:** 22 | ``` 23 | (paste your output here) 24 | ``` 25 | 26 | **Output of `vagrant service-manager box version`:** 27 | ``` 28 | (paste your output here) 29 | ``` 30 | 31 | **Steps to reproduce the issue:** 32 | 1. 33 | 2. 34 | 3. 35 | 36 | **Describe the results you received:** 37 | 38 | 39 | **Describe the results you expected:** 40 | 41 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/action/setup_network.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | module Action 4 | class SetupNetwork 5 | def initialize(app, env) 6 | @app = app 7 | @machine = env[:machine] 8 | @ui = env[:ui] 9 | end 10 | 11 | def call(env) 12 | add_private_network if virtualbox? && default_network_exists? 13 | @app.call(env) 14 | end 15 | 16 | private 17 | 18 | def virtualbox? 19 | @machine.provider.instance_of?(VagrantPlugins::ProviderVirtualBox::Provider) 20 | end 21 | 22 | def default_network_exists? 23 | @machine.config.vm.networks.length == 1 24 | end 25 | 26 | def add_private_network 27 | @ui.info I18n.t('servicemanager.actions.private_network') 28 | @machine.config.vm.network :private_network, type: :dhcp 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require 'vagrant' 3 | rescue LoadError 4 | raise 'The Vagrant vagrant-service-manager plugin must be run within Vagrant.' 5 | end 6 | 7 | require 'vagrant-service-manager/plugin' 8 | require 'vagrant-service-manager/command' 9 | 10 | module VagrantPlugins 11 | module ServiceManager 12 | SUPPORTED_HOSTS = %w(linux darwin windows).freeze 13 | 14 | # Returns the path to the source of this plugin 15 | def self.source_root 16 | @source_root ||= Pathname.new(File.expand_path('../../', __FILE__)) 17 | end 18 | 19 | # Temporally load the extra capabilities files for Red Hat 20 | load(File.join(source_root, 'plugins/guests/redhat/plugin.rb')) 21 | # Load the host capabilities files 22 | SUPPORTED_HOSTS.each do |host| 23 | load(File.join(source_root, "plugins/hosts/#{host}/plugin.rb")) 24 | end 25 | # Default I18n to load the en locale 26 | I18n.load_path << File.expand_path('locales/en.yml', source_root) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/box_version.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class BoxVersion 5 | # Prints the version of the vagrant box, parses /etc/os-release for version 6 | def self.box_version(machine, options = {}) 7 | command = "cat #{OS_RELEASE_FILE} | grep VARIANT" 8 | 9 | # TODO: execute efficient command to solve this 10 | return unless machine.communicate.test(command) # Return nil if command fails 11 | PluginLogger.debug 12 | machine.communicate.execute(command) do |type, data| 13 | if type == :stderr 14 | @env.ui.error(data) 15 | exit 126 16 | end 17 | 18 | return data.chomp if options[:script_readable] 19 | info = Hash[data.delete('"').split("\n").map { |e| e.split('=') }] 20 | return "#{info['VARIANT']} #{info['VARIANT_VERSION']}" 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/service.rb: -------------------------------------------------------------------------------- 1 | require_relative 'service_base' 2 | # Loads all services 3 | Dir["#{File.dirname(__FILE__)}/services/*.rb"].each { |f| require_relative f } 4 | 5 | module VagrantPlugins 6 | module ServiceManager 7 | SUPPORTED_BOXES = %w(adb cdk).freeze 8 | 9 | class Service 10 | def initialize(app, env) 11 | @app = app 12 | @env = env 13 | @machine = env[:machine] 14 | @service_hooks = load_service_hooks 15 | end 16 | 17 | def call(env) 18 | @app.call(env) 19 | 20 | if SUPPORTED_BOXES.include? @machine.guest.capability(:os_variant) 21 | return false unless SUPPORTED_BOXES.include? @machine.guest.capability(:os_variant) 22 | @service_hooks.each(&:execute) 23 | end 24 | rescue Vagrant::Errors::GuestCapabilityNotFound => e 25 | PluginLogger.debug e.message 26 | end 27 | 28 | private 29 | 30 | def load_service_hooks 31 | SUPPORTED_SERVICES.map { |s| PluginUtil.service_class(s).new(@machine, @env) } 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /vagrant-service-manager.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), 'lib')) 2 | require 'vagrant-service-manager/version' 3 | 4 | Gem::Specification.new do |spec| 5 | spec.name = 'vagrant-service-manager' 6 | spec.version = VagrantPlugins::ServiceManager::VERSION 7 | spec.license = 'GPL-2.0' 8 | spec.homepage = 'https://github.com/projectatomic/vagrant-service-manager' 9 | spec.summary = 'To provide the user a CLI to configure the ADB/CDK for different use cases and to '\ 10 | 'provide glue between ADB/CDK and the user\'s development environment.' 11 | spec.description = 'Provides setup information, including environment variables and certificates, '\ 12 | 'required to access services provided by ADB/CDK.' 13 | 14 | spec.authors = ['Brian Exelbierd', 'Navid Shaikh'] 15 | spec.email = ['bex@pobox.com', 'nshaikh@redhat.com'] 16 | 17 | spec.files = `git ls-files -z`.split("\x0") 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_dependency 'rubyzip', '~> 1.2.0' 21 | end 22 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/adb_kubernetes_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class ADBKubernetesBinaryHandler < ADBBinaryHandler 4 | # http://richieescarez.github.io/kubernetes/v1.0/docs/getting-started-guides/aws/kubectl.html 5 | BINARY_BASE_URL = 'https://storage.googleapis.com/kubernetes-release/release'.freeze 6 | 7 | def initialize(machine, env, options) 8 | super(machine, env, options) 9 | end 10 | 11 | def build_download_url 12 | @url = "#{BINARY_BASE_URL}/v#{@version}/bin/#{os_type}/#{arch}/kubectl#{ext}" 13 | end 14 | 15 | private 16 | 17 | def os_type 18 | if Vagrant::Util::Platform.windows? 19 | 'windows' 20 | elsif Vagrant::Util::Platform.linux? 21 | 'linux' 22 | elsif Vagrant::Util::Platform.darwin? 23 | 'darwin' 24 | end 25 | end 26 | 27 | def arch 28 | 'amd64' # only supported arch 29 | end 30 | 31 | def ext 32 | Vagrant::Util::Platform.windows? ? '.exe' : '' 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /.ci/ansible/roles/centos/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Enable centos-release-scl repo 2 | yum: name=centos-release-scl state=latest 3 | 4 | - name: Setup Vagrant 5 | yum: name={{item}} state=latest 6 | with_items: 7 | - sclo-vagrant1 8 | - rsync 9 | 10 | - name: Setup libvirt 11 | yum: name={{item}} state=latest 12 | with_items: 13 | - qemu-kvm 14 | - sclo-vagrant1-vagrant-libvirt 15 | 16 | - name: Setup VirtualBox dependencies 17 | yum: name={{item}} state=latest 18 | with_items: 19 | - gcc 20 | - kernel-devel 21 | 22 | # TODO enable when we test against VirtualBox as well 23 | #- name: Install VirtualBox 24 | # yum: name=http://download.virtualbox.org/virtualbox/rpm/rhel/7/x86_64/VirtualBox-5.0-5.0.8_103449_el7-1.x86_64.rpm state=present 25 | 26 | - name: start-enable-libvirtd 27 | service: name=libvirtd state=started enabled=yes 28 | 29 | - name: Setup Ruby dev environment 30 | yum: name={{item}} state=latest 31 | with_items: 32 | - zlib-devel 33 | - ruby-devel 34 | - rh-ruby22-ruby-devel 35 | - libvirt-devel 36 | 37 | - name: Install Development Tools 38 | yum: name="@Development tools" state=present 39 | 40 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/plugin.rb: -------------------------------------------------------------------------------- 1 | # Loads all actions 2 | Dir["#{File.dirname(__FILE__)}/action/*.rb"].each { |f| require_relative f } 3 | require_relative 'service' 4 | 5 | module VagrantPlugins 6 | module ServiceManager 7 | class Plugin < Vagrant.plugin('2') 8 | name 'service-manager' 9 | description 'Service manager for services inside vagrant box.' 10 | 11 | command 'service-manager' do 12 | require_relative 'command' 13 | Command 14 | end 15 | 16 | config 'servicemanager' do 17 | require_relative 'config' 18 | Config 19 | end 20 | 21 | service_manager_hooks = lambda do |hook| 22 | hook.before VagrantPlugins::ProviderVirtualBox::Action::Network, setup_network 23 | hook.after Vagrant::Action::Builtin::SyncedFolders, Service 24 | end 25 | 26 | action_hook :servicemanager, :machine_action_up, &service_manager_hooks 27 | action_hook :servicemanager, :machine_action_reload, &service_manager_hooks 28 | 29 | def self.setup_network 30 | Vagrant::Action::Builder.new.tap do |b| 31 | b.use Action::SetupNetwork 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/adb_docker_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class ADBDockerBinaryHandler < ADBBinaryHandler 4 | # Refer https://docs.docker.com/v1.10/engine/installation/binaries 5 | DOCKER_BINARY_BASE_URL = 'https://get.docker.com/builds'.freeze 6 | 7 | def initialize(machine, env, options) 8 | super(machine, env, options) 9 | end 10 | 11 | def build_download_url 12 | arch = @machine.env.host.capability(:os_arch) 13 | @url = "#{DOCKER_BINARY_BASE_URL}/#{os_type}/#{arch}/docker-#{@version}#{archive_ext}" 14 | end 15 | 16 | private 17 | 18 | def os_type 19 | if Vagrant::Util::Platform.windows? 20 | 'Windows' 21 | elsif Vagrant::Util::Platform.linux? 22 | 'Linux' 23 | elsif Vagrant::Util::Platform.darwin? 24 | 'Darwin' 25 | end 26 | end 27 | 28 | def archive_ext 29 | # https://github.com/docker/docker/blob/v1.11.0-rc1/CHANGELOG.md#1110-2016-04-12 30 | if @version == 'latest' || Gem::Version.new(@version) > Gem::Version.new('1.10.3') 31 | Vagrant::Util::Platform.windows? ? '.zip' : '.tgz' 32 | else 33 | binary_ext 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2016-10-14 23:34:08 +0530 using RuboCop version 0.44.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | Metrics/ClassLength: 10 | Max: 209 11 | Exclude: 12 | - 'lib/vagrant-service-manager/command.rb' 13 | 14 | Metrics/MethodLength: 15 | Max: 20 16 | Exclude: 17 | - 'lib/vagrant-service-manager/command.rb' 18 | 19 | Metrics/ModuleLength: 20 | Exclude: 21 | - 'lib/vagrant-service-manager/plugin_util.rb' 22 | 23 | Metrics/CyclomaticComplexity: 24 | Max: 9 25 | Exclude: 26 | - 'lib/vagrant-service-manager/command.rb' 27 | 28 | Metrics/PerceivedComplexity: 29 | Max: 9 30 | Exclude: 31 | - 'lib/vagrant-service-manager/command.rb' 32 | 33 | Metrics/BlockLength: 34 | Exclude: 35 | - 'Rakefile' 36 | - 'test/vagrant-service-manager/*.rb' 37 | - 'test/vagrant-service-manager/binary_handlers/*.rb' 38 | 39 | Metrics/AbcSize: 40 | Max: 20 41 | Exclude: 42 | - 'lib/vagrant-service-manager/command.rb' 43 | - 'Rakefile' 44 | 45 | Lint/Eval: 46 | Enabled: false 47 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/adb_openshift_binary_handler.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class ADBOpenshiftBinaryHandler < ADBBinaryHandler 4 | OC_BINARY_BASE_URL = 'https://github.com/openshift/origin/releases'.freeze 5 | OC_FILE_PREFIX = 'openshift-origin-client-tools'.freeze 6 | 7 | attr_reader :url 8 | 9 | def initialize(machine, env, options) 10 | super(machine, env, options) 11 | end 12 | 13 | def build_download_url 14 | download_base_path = "#{OC_BINARY_BASE_URL}/download/v#{@version}/" 15 | file = "#{OC_FILE_PREFIX}-v#{@version}-#{version_sha}-#{archive_ext}" 16 | @url = download_base_path + file 17 | end 18 | 19 | private 20 | 21 | def version_sha 22 | tag_url = "#{OC_BINARY_BASE_URL}/tag/v#{@version}" 23 | data = Net::HTTP.get(URI(tag_url)) 24 | tokens = data.match("-v#{@version}-(.*)-#{archive_ext}").captures 25 | tokens.first unless tokens.empty? 26 | rescue StandardError 27 | raise I18n.t('servicemanager.commands.install_cli.unsupported_version') 28 | end 29 | 30 | def os_type 31 | if Vagrant::Util::Platform.windows? 32 | 'windows' 33 | elsif Vagrant::Util::Platform.linux? 34 | 'linux' 35 | elsif Vagrant::Util::Platform.darwin? 36 | 'mac' 37 | end 38 | end 39 | 40 | def arch 41 | arch = @machine.env.host.capability(:os_arch) 42 | arch == 'x86_64' ? '64' : '32' 43 | end 44 | 45 | def archive_ext 46 | os_type + (os_type == 'linux' ? "-#{arch}bit.tar.gz" : '.zip') 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/archive_handler_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | module VagrantPlugins 4 | module ServiceManager 5 | describe 'Archive Handlers' do 6 | before do 7 | @machine = fake_machine 8 | 9 | # set test path 10 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 11 | end 12 | 13 | after do 14 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 15 | end 16 | 17 | describe TarHandler do 18 | it "should unpack '.tgz' archive properly" do 19 | test_archive_path = "#{test_data_dir_path}/docker-1.11.0.tgz" 20 | dest_binary_path = @plugin_test_path + '/docker-1.11.0' 21 | regex = %r{\/docker$} 22 | 23 | TarHandler.new(test_archive_path, dest_binary_path, regex).unpack 24 | assert_equal(File.exist?(dest_binary_path), true) 25 | end 26 | 27 | it "should unpack '.tar.gz' archive properly" do 28 | test_archive_path = "#{test_data_dir_path}/docker-1.10.0.tar.gz" 29 | dest_binary_path = @plugin_test_path + '/docker-1.10.0' 30 | regex = %r{\/docker$} 31 | 32 | TarHandler.new(test_archive_path, dest_binary_path, regex).unpack 33 | assert_equal(File.exist?(dest_binary_path), true) 34 | end 35 | end 36 | 37 | describe ZipHandler do 38 | it "should unpack '.zip' archive properly" do 39 | test_archive_path = "#{test_data_dir_path}/docker-1.9.1.zip" 40 | dest_binary_path = @plugin_test_path + '/docker-1.9.1' 41 | regex = %r{\/docker.exe$} 42 | 43 | ZipHandler.new(test_archive_path, dest_binary_path, regex).unpack 44 | assert_equal(File.exist?(dest_binary_path), true) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/config.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | 3 | module VagrantPlugins 4 | module ServiceManager 5 | SERVICES = %w(docker openshift kubernetes).freeze 6 | BASE_CONFIG = [:services].freeze 7 | OPENSHIFT_CONFIG = [ 8 | :openshift_docker_registry, :openshift_image_name, :openshift_image_tag 9 | ].freeze 10 | PROXY_CONFIG = [:proxy, :proxy_user, :proxy_password].freeze 11 | 12 | class Config < Vagrant.plugin('2', :config) 13 | attr_accessor(*(BASE_CONFIG + OPENSHIFT_CONFIG + PROXY_CONFIG)) 14 | 15 | DEFAULTS = { 16 | services: '' 17 | }.freeze 18 | 19 | def initialize 20 | super 21 | @services = UNSET_VALUE 22 | end 23 | 24 | def finalize! 25 | DEFAULTS.each do |name, value| 26 | if instance_variable_get('@' + name.to_s) == UNSET_VALUE 27 | instance_variable_set '@' + name.to_s, value 28 | end 29 | end 30 | end 31 | 32 | def validate(_machine) 33 | errors = _detected_errors 34 | errors.concat(validate_services) 35 | { 'servicemanager' => errors } 36 | end 37 | 38 | private 39 | 40 | def validate_services 41 | errors = [] 42 | 43 | unless supported_services? 44 | errors << I18n.t('servicemanager.config.supported_devices', 45 | services: SERVICES.inspect) 46 | end 47 | 48 | if SERVICES.drop(1).to_set.subset? configured_services.to_set 49 | errors << I18n.t('servicemanager.config.only_one_service') 50 | end 51 | 52 | errors 53 | end 54 | 55 | def supported_services? 56 | configured_services.to_set.subset? SERVICES.to_set 57 | end 58 | 59 | def configured_services 60 | @services.split(',').map(&:strip) 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/installer.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class Installer 4 | def initialize(machine, env, options) 5 | @options = options 6 | @type = @options[:type] 7 | @machine = machine 8 | @env = env 9 | @option_msg = ' ' + format_options 10 | 11 | validate_prerequisites 12 | binary_handler_class = Object.const_get(handler_class) 13 | @binary_handler = binary_handler_class.new(machine, env, @options) 14 | end 15 | 16 | def handler_class 17 | "#{ServiceManager.name}::#{@options[:box_version].upcase}#{@type.capitalize}BinaryHandler" 18 | end 19 | 20 | def install 21 | @binary_handler.handle_windows_binary_path if Vagrant::Util::Platform.windows? 22 | unless PluginUtil.binary_downloaded?(@binary_handler.path) 23 | @binary_handler.binary_exists = false 24 | @binary_handler.install 25 | end 26 | 27 | @binary_handler.print_message(@option_msg) 28 | end 29 | 30 | def format_options 31 | msg = '' 32 | msg = "--cli-version #{@options['--cli-version']}" unless @options['--cli-version'].nil? 33 | msg = "--path #{@options['--path']}" + ' ' + msg unless @options['--path'].nil? 34 | msg.strip 35 | end 36 | 37 | private 38 | 39 | def validate_prerequisites 40 | unless PluginUtil.service_running?(@machine, @type.to_s) 41 | @env.ui.info I18n.t('servicemanager.commands.install_cli.service_not_enabled', 42 | service: @type) 43 | exit 126 44 | end 45 | 46 | # return if --path is not specified 47 | return unless @options.key?('--path') 48 | return if File.exist?(@options['--path']) 49 | @env.ui.info I18n.t('servicemanager.commands.install_cli.invalid_binary_path', dir_path: dir_name) 50 | exit 126 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /test/fake_https_server.rb: -------------------------------------------------------------------------------- 1 | require 'webrick/https' 2 | 3 | class FakeHTTPSServer < WEBrick::HTTPServer 4 | HTTPS_SERVER_DEFAULT_PORT = 8443 5 | CERT_NAME = [%w(CN localhost)].freeze 6 | 7 | def self.start(port = HTTPS_SERVER_DEFAULT_PORT) 8 | @https_server = FakeHTTPSServer.new(port) 9 | Thread.new do 10 | @https_server.start 11 | end 12 | 13 | @https_server 14 | end 15 | 16 | def self.stop 17 | @https_server.shutdown unless @https_server.nil? 18 | end 19 | 20 | def initialize(port) 21 | # we need to temporarily capture stderr, since WEBrick::Utils::create_self_signed_cert prints to stderr 22 | capture_stderr do 23 | @url_to_filename = {} 24 | @url_request_received = {} 25 | @log = StringIO.new 26 | logger = WEBrick::Log.new(@log) 27 | access_log = [[@log, 'STATUS=%s URL=%{url}n BODY=%{body}n']] 28 | super(Port: port, SSLEnable: true, SSLCertName: CERT_NAME, Logger: logger, AccessLog: access_log) 29 | end 30 | end 31 | 32 | def service(req, res) 33 | uri = req.request_uri.to_s 34 | return unless @url_to_filename.key?(uri) 35 | @url_request_received[uri] = true 36 | res.content_type = 'application/octet-stream' 37 | 38 | open(@url_to_filename[uri], 'r') do |file| 39 | file.write(res.body) 40 | end 41 | end 42 | 43 | def expect_and_respond(url, filename) 44 | @url_to_filename[url] = filename 45 | @url_request_received[url] = false 46 | end 47 | 48 | def assert_requests 49 | @url_request_received.values.reduce do |memo, received| 50 | memo && received 51 | end 52 | end 53 | 54 | private 55 | 56 | def capture_stderr 57 | # The output stream must be an IO-like object. In this case we capture it in 58 | # an in-memory IO object so we can return the string value. You can assign any 59 | # IO object here. 60 | previous_stderr = $stderr 61 | $stderr = StringIO.new 62 | yield 63 | $stderr.string 64 | ensure 65 | # Restore the previous value of stderr (typically equal to STDERR). 66 | $stderr = previous_stderr 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/service_base.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class ServiceBase 4 | def initialize(machine, env) 5 | @machine = machine 6 | @env = env 7 | @ui = env.respond_to?('ui') ? env.ui : env[:ui] 8 | @services = @machine.config.servicemanager.services.split(',').map(&:strip) 9 | home_path = env.respond_to?('home_path') ? env.home_path : env[:home_path] 10 | @plugin_dir = File.join(home_path, 'data', 'service-manager') 11 | end 12 | 13 | def service_start_allowed? 14 | true # always start service by default 15 | end 16 | 17 | def cdk? 18 | @machine.guest.capability(:os_variant) == 'cdk' 19 | end 20 | 21 | def proxy_cmd_options 22 | options = '' 23 | 24 | return options unless proxy_settings_valid? 25 | 26 | PROXY_CONFIG.each do |key| 27 | options += "#{key.to_s.upcase}='#{@machine.config.servicemanager.send(key)}' " 28 | end 29 | 30 | options.chop 31 | end 32 | 33 | def proxy_settings_valid? 34 | proxy = @machine.config.servicemanager.send('proxy') 35 | user = @machine.config.servicemanager.send('proxy_user') 36 | password = @machine.config.servicemanager.send('proxy_password') 37 | 38 | if proxy && user.nil? && password.nil? || (proxy && user && password) 39 | PluginLogger.debug('Detected proxy settings. Going to apply them to service commands.') 40 | values = "Proxy URL : #{proxy}" 41 | values += ", User : #{user}, Password: *** " unless user.nil? 42 | PluginLogger.debug(values) 43 | return true 44 | end 45 | 46 | warn_proxy_settings_missing(proxy, user, password) 47 | false 48 | end 49 | 50 | def warn_proxy_settings_missing(proxy, user, password) 51 | # Check if user try to set proxy 52 | return if proxy.nil? && user.nil? && password.nil? 53 | message = 'Proxy URL is missing' if proxy.nil? 54 | message = 'Either user or password is missing.' if proxy && user.nil? || proxy && password.nil? 55 | @ui.warn message 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /features/kubernetes.feature: -------------------------------------------------------------------------------- 1 | Feature: Command output from various Kubernetes related commands 2 | service-manager should return the correct output from commands affecting Kubernetes 3 | 4 | Scenario Outline: Boot and execute commands 5 | Given box is 6 | And provider is 7 | And a file named "Vagrantfile" with: 8 | """ 9 | begin 10 | require 'vagrant-libvirt' 11 | rescue LoadError 12 | # NOOP 13 | end 14 | 15 | Vagrant.configure('2') do |config| 16 | config.vm.box = '' 17 | config.vm.box_url = 'file://../../.boxes/-.box' 18 | config.vm.network :private_network, ip: '' 19 | config.vm.synced_folder '.', '/vagrant', disabled: true 20 | 21 | config.servicemanager.services = 'kubernetes' 22 | end 23 | """ 24 | 25 | When I successfully run `bundle exec vagrant up --provider ` 26 | When I successfully run `bundle exec vagrant service-manager status kubernetes` 27 | Then stdout from "bundle exec vagrant service-manager status kubernetes" should contain "kubernetes - running" 28 | 29 | When I run `bundle exec vagrant service-manager install-cli kubernetes` 30 | Then the exit status should be 0 31 | And the binary "kubectl" should be installed 32 | 33 | When I successfully run `bundle exec vagrant service-manager env kubernetes` 34 | Then stdout from "bundle exec vagrant service-manager env kubernetes" should be evaluable in a shell 35 | And stdout from "bundle exec vagrant service-manager env kubernetes" should match /export KUBECONFIG=.*\/.vagrant.d\/data\/service-manager\/kubeconfig/ 36 | And stdout from "bundle exec vagrant service-manager env kubernetes" should match /# eval "\$\(vagrant service-manager env kubernetes\)"/ 37 | 38 | When I successfully run `bundle exec vagrant service-manager env kubernetes --script-readable` 39 | Then stdout from "bundle exec vagrant service-manager env kubernetes --script-readable" should be script readable 40 | 41 | Examples: 42 | | box | provider | ip | 43 | | adb | virtualbox | 10.10.10.42 | 44 | | cdk | virtualbox | 10.10.10.42 | 45 | | adb | libvirt | 10.10.10.42 | 46 | | cdk | libvirt | 10.10.10.42 | 47 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/services/kubernetes.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class Kubernetes < ServiceBase 4 | def initialize(machine, env) 5 | super(machine, env) 6 | @service_name = 'kubernetes' 7 | @kubeconfig_path = "#{@plugin_dir}/kubeconfig" 8 | end 9 | 10 | def execute 11 | if service_start_allowed? 12 | command = 'sccli kubernetes' 13 | command = "#{proxy_cmd_options} #{command}" unless proxy_cmd_options.empty? 14 | 15 | exit_code = PluginUtil.execute_and_exit_on_fail(@machine, @ui, command) 16 | 17 | if exit_code.zero? 18 | PluginUtil.generate_kubeconfig(@machine, @ui, @plugin_dir) 19 | @ui.info I18n.t('servicemanager.actions.service_success', service: 'Kubernetes') 20 | else 21 | @ui.info I18n.t('servicemanager.actions.service_failure', service: 'Kubernetes') 22 | end 23 | end 24 | rescue StandardError => e 25 | @ui.error e.message.squeeze 26 | exit 126 27 | end 28 | 29 | def status 30 | PluginUtil.print_service_status(@ui, @machine, @service_name) 31 | end 32 | 33 | def info(options = {}) 34 | if PluginUtil.service_running?(@machine, @service_name) 35 | options[:kubeconfig_path] = @kubeconfig_path 36 | print_env_info(options) 37 | else 38 | @ui.error I18n.t('servicemanager.commands.env.service_not_running', 39 | name: @service_name) 40 | exit 126 41 | end 42 | end 43 | 44 | def service_start_allowed? 45 | @services.include?('kubernetes') 46 | end 47 | 48 | private 49 | 50 | def print_env_info(options) 51 | PluginLogger.debug("script_readable: #{options[:script_readable] || false}") 52 | 53 | label = PluginUtil.env_label(options[:script_readable]) 54 | message = I18n.t("servicemanager.commands.env.kubernetes.#{label}", 55 | kubeconfig_path: options[:kubeconfig_path]) 56 | @ui.info(message) 57 | 58 | return if options[:script_readable] || options[:all] 59 | PluginUtil.print_shell_configure_info(@ui, ' kubernetes') 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /test/fake_http_proxy.rb: -------------------------------------------------------------------------------- 1 | require 'webrick' 2 | require 'webrick/https' 3 | require 'webrick/httpproxy' 4 | require 'webrick/httpstatus' 5 | 6 | require_relative 'fake_https_server' 7 | 8 | class FakeHTTPProxyServer < WEBrick::HTTPProxyServer 9 | DEFAULT_PORT = 7000 10 | 11 | def self.start(tmp_dir, port = DEFAULT_PORT, authenticated = false) 12 | @proxy_server = FakeHTTPProxyServer.new(tmp_dir, port, authenticated) 13 | Thread.new do 14 | @proxy_server.start 15 | end 16 | 17 | @proxy_server 18 | end 19 | 20 | def self.stop 21 | @proxy_server.shutdown unless @proxy_server.nil? 22 | end 23 | 24 | def initialize(tmp_dir, port, authenticated) 25 | @fake_https_server = "localhost:#{FakeHTTPSServer::HTTPS_SERVER_DEFAULT_PORT}" 26 | @connect_request_received = {} 27 | @log = StringIO.new 28 | config = { 29 | Port: port, 30 | Logger: WEBrick::Log.new(@log), 31 | AccessLog: [[@log, WEBrick::AccessLog::COMBINED_LOG_FORMAT]] 32 | } 33 | if authenticated 34 | authenticator = WEBrick::HTTPAuth::ProxyBasicAuth.new(get_auth_options(tmp_dir)) 35 | config[:ProxyAuthProc] = authenticator.method(:authenticate).to_proc 36 | end 37 | super(config) 38 | end 39 | 40 | def service(req, res) 41 | if req.request_method == 'CONNECT' 42 | # redirect HTTPS traffic to our fake HTTPS server 43 | @connect_request_received[req.unparsed_uri] = true if @connect_request_received.key? req.unparsed_uri 44 | req.instance_variable_set(:@unparsed_uri, @fake_https_server) 45 | do_CONNECT(req, res) 46 | elsif req.unparsed_uri =~ %r{^http://} 47 | proxy_service(req, res) 48 | else 49 | super(req, res) 50 | end 51 | end 52 | 53 | def expect_http_connect(host_and_port) 54 | @connect_request_received[host_and_port] = false 55 | end 56 | 57 | def assert_connect_requests 58 | @connect_request_received.values.reduce do |memo, received| 59 | memo && received 60 | end 61 | end 62 | 63 | private 64 | 65 | def get_auth_options(tmp_dir) 66 | htpasswd = WEBrick::HTTPAuth::Htpasswd.new File.join(tmp_dir, '.htpasswd') 67 | htpasswd.set_passwd 'Proxy Realm', 'user', 'password' 68 | htpasswd.flush 69 | { 70 | Realm: 'Proxy Realm', 71 | UserDB: htpasswd, 72 | Logger: WEBrick::Log.new(@log) 73 | } 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/service_base_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | require 'vagrant-service-manager/config' 3 | require 'vagrant-service-manager/plugin_util' 4 | 5 | module VagrantPlugins 6 | describe ServiceManager::ServiceBase do 7 | let(:machine) { fake_machine } 8 | let(:instance) { ServiceManager::ServiceBase.new(machine, machine.env) } 9 | 10 | it 'should build the proxy options if only proxy url is given' do 11 | machine.config.servicemanager.proxy = 'foo:8080' 12 | options = instance.proxy_cmd_options 13 | assert_match(/PROXY='foo:8080'/, options) 14 | end 15 | 16 | it 'should build the proxy options if all proxy settings are given' do 17 | machine.config.servicemanager.proxy = 'foo:8080' 18 | machine.config.servicemanager.proxy_user = 'user' 19 | machine.config.servicemanager.proxy_password = 'password' 20 | 21 | options = instance.proxy_cmd_options 22 | assert_match(/PROXY='foo:8080'/, options) 23 | assert_match(/PROXY_USER='user'/, options) 24 | assert_match(/PROXY_PASSWORD='password'/, options) 25 | end 26 | 27 | it 'should return empty proxy options if proxy url is not given' do 28 | machine.config.servicemanager.proxy_user = 'user' 29 | machine.config.servicemanager.proxy_password = 'password' 30 | 31 | options = instance.proxy_cmd_options 32 | assert_match(options, '') 33 | end 34 | 35 | it 'should return empty proxy options if user name not given' do 36 | machine.config.servicemanager.proxy = 'foo:8080' 37 | machine.config.servicemanager.proxy_password = 'password' 38 | 39 | options = instance.proxy_cmd_options 40 | assert_match(options, '') 41 | end 42 | 43 | it 'should return empty proxy options if password not given' do 44 | machine.config.servicemanager.proxy = 'foo:8080' 45 | machine.config.servicemanager.proxy_user = 'user' 46 | 47 | options = instance.proxy_cmd_options 48 | assert_match(options, '') 49 | end 50 | 51 | it 'should pass proxy settings as specified via Vagrant config' do 52 | machine.config.servicemanager.proxy = 'foo:8080' 53 | machine.config.servicemanager.proxy_user = 'user' 54 | machine.config.servicemanager.proxy_password = 'password' 55 | command = "#{instance.proxy_cmd_options} sccli openshift" 56 | 57 | ServiceManager::PluginUtil.execute_once(machine, FakeUI, command) 58 | 59 | command_executed = machine.communicate.commands[:sudo].first 60 | 61 | assert_match(/PROXY='foo:8080'/, command_executed) 62 | assert_match(/PROXY_USER='user'/, command_executed) 63 | assert_match(/PROXY_PASSWORD='password'/, command_executed) 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /features/help.feature: -------------------------------------------------------------------------------- 1 | Feature: Command output from help command 2 | service-manager should return the correct output from its help commands 3 | 4 | Scenario: Boot and execute help commands 5 | When I successfully run `bundle exec vagrant service-manager --help` 6 | Then stdout from "bundle exec vagrant service-manager --help" should contain: 7 | """ 8 | Usage: vagrant service-manager [options] 9 | 10 | Commands: 11 | env displays connection information for services in the box 12 | box displays box related information like version, release, IP etc 13 | restart restarts the given service in the box 14 | start starts the given service in the box 15 | stop stops the given service in the box 16 | status list services and their running state 17 | install-cli install the client binary for the specified service 18 | 19 | Options: 20 | -h, --help print this help 21 | 22 | For help on any individual command run `vagrant service-manager COMMAND -h` 23 | """ 24 | 25 | When I successfully run `bundle exec vagrant service-manager -h` 26 | Then stdout from "bundle exec vagrant service-manager -h" should contain: 27 | """ 28 | Usage: vagrant service-manager [options] 29 | 30 | Commands: 31 | env displays connection information for services in the box 32 | box displays box related information like version, release, IP etc 33 | restart restarts the given service in the box 34 | start starts the given service in the box 35 | stop stops the given service in the box 36 | status list services and their running state 37 | install-cli install the client binary for the specified service 38 | 39 | Options: 40 | -h, --help print this help 41 | 42 | For help on any individual command run `vagrant service-manager COMMAND -h` 43 | """ 44 | 45 | When I run `bundle exec vagrant service-manager` 46 | Then the exit status should be 1 47 | And stdout from "bundle exec vagrant service-manager -h" should contain: 48 | """ 49 | Usage: vagrant service-manager [options] 50 | 51 | Commands: 52 | env displays connection information for services in the box 53 | box displays box related information like version, release, IP etc 54 | restart restarts the given service in the box 55 | start starts the given service in the box 56 | stop stops the given service in the box 57 | status list services and their running state 58 | install-cli install the client binary for the specified service 59 | 60 | Options: 61 | -h, --help print this help 62 | 63 | For help on any individual command run `vagrant service-manager COMMAND -h` 64 | """ 65 | 66 | 67 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/proxy_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | require 'vagrant/util/downloader' 3 | require 'uri' 4 | 5 | module VagrantPlugins 6 | module ServiceManager 7 | describe 'Proxy Test' do 8 | before do 9 | @machine = fake_machine 10 | 11 | # Set test path 12 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 13 | ServiceManager.temp_dir = "#{@plugin_test_path}/temp" 14 | ServiceManager.bin_dir = "#{@plugin_test_path}/bin" 15 | 16 | # Allow insecure curl 17 | ENV['CURL_INSECURE'] = 'true' 18 | 19 | # Set up the handler under test 20 | options = { type: :openshift, '--cli-version' => '1.2.0' } 21 | @handler = ADBOpenshiftBinaryHandler.new(@machine, @machine.env, options) 22 | @handler.build_download_url 23 | @handler.validate_url 24 | @handler.build_archive_path 25 | @handler.ensure_binary_and_temp_directories 26 | 27 | dirname = File.dirname(__FILE__) 28 | @filename = File.join(dirname, '..', 'test_data', URI(@handler.url).path.split('/').last.to_s) 29 | end 30 | 31 | after do 32 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 33 | FakeHTTPSServer.stop 34 | FakeHTTPProxyServer.stop 35 | end 36 | 37 | describe 'Unauthenticated proxy environment' do 38 | before do 39 | @http_proxy = FakeHTTPProxyServer.start ServiceManager.temp_dir 40 | @https_server = FakeHTTPSServer.start 41 | 42 | @machine.config.servicemanager.proxy = "http://localhost:#{FakeHTTPProxyServer::DEFAULT_PORT}" 43 | end 44 | 45 | it 'client binary download request should pass through proxy' do 46 | @http_proxy.expect_http_connect('github.com:443') 47 | @https_server.expect_and_respond(@handler.url, @filename) 48 | 49 | @handler.download_archive 50 | 51 | @http_proxy.assert_connect_requests.must_equal true 52 | @https_server.assert_requests.must_equal true 53 | end 54 | end 55 | 56 | describe 'Authenticated proxy environment' do 57 | before do 58 | @http_proxy = FakeHTTPProxyServer.start(ServiceManager.temp_dir, 59 | FakeHTTPProxyServer::DEFAULT_PORT, true) 60 | @https_server = FakeHTTPSServer.start 61 | 62 | @machine.config.servicemanager.proxy = "http://localhost:#{FakeHTTPProxyServer::DEFAULT_PORT}" 63 | @machine.config.servicemanager.proxy_user = 'user' 64 | @machine.config.servicemanager.proxy_password = 'password' 65 | end 66 | 67 | it 'client binary download request should pass through proxy' do 68 | @http_proxy.expect_http_connect('github.com:443') 69 | @https_server.expect_and_respond(@handler.url, @filename) 70 | 71 | @handler.download_archive 72 | 73 | @http_proxy.assert_connect_requests.must_equal true 74 | @https_server.assert_requests.must_equal true 75 | end 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.push(File.expand_path('../../plugins', __FILE__)) 2 | $LOAD_PATH.push(File.expand_path('../../lib', __FILE__)) 3 | $LOAD_PATH.push(File.expand_path('../../locales', __FILE__)) 4 | 5 | require 'bundler/setup' 6 | require 'minitest/spec' 7 | require 'minitest/autorun' 8 | require 'mocha/mini_test' 9 | 10 | require 'vagrant-service-manager' 11 | require 'guests/redhat/cap/box_version' 12 | require 'guests/redhat/cap/os_variant' 13 | 14 | require_relative 'fake_http_proxy' 15 | require_relative 'fake_https_server' 16 | 17 | def fake_environment(options = { enabled: true }) 18 | { machine: fake_machine(options), ui: FakeUI } 19 | end 20 | 21 | class FakeUI 22 | attr_reader :received_info_messages 23 | 24 | def initialize 25 | @received_info_messages = [] 26 | end 27 | 28 | def info(*args) 29 | # puts "#{args}" 30 | @received_info_messages << args[0] 31 | end 32 | end 33 | 34 | class RecordingCommunicator 35 | attr_reader :commands, :responses 36 | 37 | def initialize 38 | @commands = Hash.new([]) 39 | @responses = Hash.new('') 40 | end 41 | 42 | def stub_command(command, response) 43 | responses[command] = response 44 | end 45 | 46 | def sudo(command) 47 | commands[:sudo] << command 48 | responses[command] 49 | end 50 | 51 | def execute(command) 52 | commands[:execute] << command 53 | responses[command].split("\n").each do |line| 54 | yield(:stdout, "#{line}\n") 55 | end 56 | end 57 | 58 | def test(command) 59 | commands[:test] << command 60 | true 61 | end 62 | 63 | def ready? 64 | true 65 | end 66 | end 67 | 68 | module ServiceManager 69 | class FakeProvider 70 | def initialize(*args) 71 | end 72 | 73 | def _initialize(*args) 74 | end 75 | 76 | def ssh_info 77 | end 78 | 79 | def state 80 | @state ||= Vagrant::MachineState.new('fake-state', 'fake-state', 'fake-state') 81 | end 82 | end 83 | 84 | class FakeConfig 85 | def servicemanager 86 | @servicemanager_config ||= VagrantPlugins::ServiceManager::Config.new 87 | end 88 | 89 | def vm 90 | VagrantPlugins::Kernel_V2::VMConfig.new 91 | end 92 | end 93 | end 94 | 95 | def fake_machine(options = {}) 96 | env = options.fetch(:env, Vagrant::Environment.new) 97 | 98 | machine = Vagrant::Machine.new( 99 | 'fake_machine', 100 | 'fake_provider', 101 | ServiceManager::FakeProvider, 102 | 'provider_config', 103 | {}, # provider_options 104 | env.vagrantfile.config, # config 105 | Pathname('data_dir'), 106 | 'box', 107 | options.fetch(:env, Vagrant::Environment.new), 108 | env.vagrantfile 109 | ) 110 | 111 | machine.instance_variable_set('@communicator', RecordingCommunicator.new) 112 | machine.config.vm.hostname = options.fetch(:hostname, 'somehost.vagrant.test') 113 | machine 114 | end 115 | 116 | def test_data_dir_path 117 | File.expand_path('test_data', File.dirname(__FILE__)) 118 | end 119 | 120 | module MiniTest 121 | class Spec 122 | alias hush capture_io 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /.ci/jenkins-execute-script.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import json 5 | import urllib 6 | import subprocess 7 | import sys 8 | 9 | url_base = "http://admin.ci.centos.org:8080" 10 | api_key = os.environ['API_KEY'] 11 | count = os.environ['MACHINE_COUNT'] if os.environ.get('MACHINE_COUNT') != None else "1" 12 | ver = "7" 13 | arch = "x86_64" 14 | req_url = "%s/Node/get?key=%s&ver=%s&arch=%s&count=%s" % (url_base, api_key, ver, arch, count) 15 | 16 | jsondata = urllib.urlopen(req_url).read() 17 | data = json.loads(jsondata) 18 | 19 | # Setup some variables. Can be passed as env variables via the job config. Otherwise defaults apply 20 | repo_url = os.environ['REPO_URL'] if os.environ.get('REPO_URL') != None else 'https://github.com/projectatomic/vagrant-service-manager.git' 21 | branch = os.environ['BRANCH'] if os.environ.get('BRANCH') != None else 'master' 22 | 23 | def execute_on_host( host, cmd, error_message ): 24 | # build command to execute install and test commands via ssh 25 | ssh_cmd = "ssh -t -t " 26 | ssh_cmd += "-o UserKnownHostsFile=/dev/null " 27 | ssh_cmd += "-o StrictHostKeyChecking=no " 28 | ssh_cmd += "root@%s " % (host) 29 | 30 | cmd = '%s "%s"' % (ssh_cmd, cmd) 31 | print "Executing: %s" % (cmd) 32 | exit_code = subprocess.call(cmd, shell=True) 33 | if exit_code != 0 : sys.exit(error_message) 34 | return 35 | 36 | def prepare_pull_request_build(host): 37 | pr_branch = os.environ['ghprbSourceBranch'] 38 | pr_author_repo = os.environ['ghprbAuthorRepoGitUrl'] 39 | 40 | branch_cmd = 'cd vagrant-service-manager && ' 41 | branch_cmd += "git checkout -b %s" % (pr_branch) 42 | execute_on_host(host, branch_cmd, "Unable to create branch for pull request build") 43 | 44 | pull_cmd = 'cd vagrant-service-manager && ' 45 | pull_cmd += "git pull --no-edit %s %s " % (pr_author_repo, pr_branch) 46 | execute_on_host(host, pull_cmd, "Unable to pull pull request") 47 | return 48 | 49 | for host in data['hosts']: 50 | 51 | # run the Ansible playbook 52 | ansible_cmd = 'yum -y install git epel-release ansible1.9 && ' 53 | ansible_cmd += 'yum -y install ansible1.9 && ' 54 | ansible_cmd += 'git clone %s && ' % repo_url 55 | ansible_cmd += 'cd vagrant-service-manager && ' 56 | ansible_cmd += 'git checkout %s && ' % branch 57 | ansible_cmd += 'cd .ci/ansible && ' 58 | ansible_cmd += 'ANSIBLE_NOCOLOR=1 ansible-playbook site.yml' 59 | execute_on_host(host, ansible_cmd, "Ansible playbook failed") 60 | 61 | # if we deal with a pull request build we need to prepare the source 62 | if os.environ.get('ghprbPullId') != None: 63 | prepare_pull_request_build(host) 64 | 65 | # setup the environment 66 | setup_cmd = 'cd vagrant-service-manager && ' 67 | setup_cmd += 'gem install bundler -v 1.12.5 && ' 68 | setup_cmd += 'bundle install --no-color' 69 | execute_on_host(host, setup_cmd, "Unable to setup Ruby environment") 70 | 71 | # run build and features 72 | build_cmd = 'cd vagrant-service-manager && ' 73 | build_cmd += 'bundle exec rake rubocop && ' 74 | build_cmd += 'bundle exec rake test && ' 75 | build_cmd += 'bundle exec rake features CUCUMBER_OPTS=\'-p ci\' PROVIDER=libvirt BOX=adb,cdk && ' 76 | build_cmd += 'bundle exec rake build' 77 | 78 | execute_on_host(host, build_cmd, "Tests failures") 79 | 80 | done_nodes_url = "%s/Node/done?key=%s&sside=%s" % (url_base, api_key, data['ssid']) 81 | print urllib.urlopen(done_nodes_url) 82 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/services/docker.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class Docker < ServiceBase 4 | # Hard Code the Docker port because it is fixed on the VM 5 | # This also makes it easier for the plugin to be cross-provider 6 | PORT = 2376 7 | 8 | def initialize(machine, env) 9 | super(machine, env) 10 | @service_name = 'docker' 11 | end 12 | 13 | def execute 14 | if service_start_allowed? 15 | command = 'sudo rm -f /etc/docker/ca.pem && sudo systemctl restart docker' 16 | exit_code = PluginUtil.execute_and_exit_on_fail(@machine, @ui, command) 17 | 18 | # Copy certs on command execution success 19 | if exit_code.zero? 20 | secrets_path = PluginUtil.host_docker_path(@machine) 21 | PluginUtil.copy_certs_to_host(@machine, secrets_path, @ui) 22 | @ui.info I18n.t('servicemanager.actions.service_success', service: 'Docker') 23 | else 24 | @ui.info I18n.t('servicemanager.actions.service_failure', service: 'Docker') 25 | end 26 | end 27 | rescue StandardError => e 28 | @ui.error e.message.squeeze 29 | exit 126 30 | end 31 | 32 | def status 33 | PluginUtil.print_service_status(@ui, @machine, @service_name) 34 | end 35 | 36 | def info(options = {}) 37 | if PluginUtil.service_running?(@machine, @service_name) 38 | options[:secrets_path] = PluginUtil.host_docker_path(@machine) 39 | options[:guest_ip] = PluginUtil.machine_ip(@machine) 40 | 41 | # Verify valid certs and copy if invalid 42 | unless PluginUtil.certs_present_and_valid?(options[:secrets_path], @machine) 43 | # Log the message prefixed by # 44 | PluginUtil.copy_certs_to_host(@machine, options[:secrets_path], @ui, true) 45 | end 46 | 47 | api_version_cmd = "docker version --format '{{.Server.APIVersion}}'" 48 | unless @machine.communicate.test(api_version_cmd) 49 | # fix for issue #152: Fallback to older Docker version (< 1.9.1) 50 | api_version_cmd.gsub!(/APIVersion/, 'ApiVersion') 51 | end 52 | 53 | options[:api_version] = PluginUtil.execute_once(@machine, @ui, api_version_cmd) 54 | # Display the information, irrespective of the copy operation 55 | print_env_info(options) 56 | else 57 | @ui.error I18n.t('servicemanager.commands.env.service_not_running', 58 | name: @service_name) 59 | exit 126 60 | end 61 | end 62 | 63 | private 64 | 65 | def print_env_info(options) 66 | PluginLogger.debug("script_readable: #{options[:script_readable] || false}") 67 | 68 | label = PluginUtil.env_label(options[:script_readable]) 69 | 70 | if Vagrant::Util::Platform.windows? 71 | options[:secrets_path] = PluginUtil.windows_path(options[:secrets_path]) 72 | end 73 | message = I18n.t("servicemanager.commands.env.docker.#{label}", 74 | ip: options[:guest_ip], port: PORT, path: options[:secrets_path], 75 | api_version: options[:api_version]) 76 | # Puts is used to escape and render the back slashes in Windows path 77 | message = puts(message) if Vagrant::Util::Platform.windows? 78 | @ui.info(message) 79 | return if options[:script_readable] || options[:all] 80 | PluginUtil.print_shell_configure_info(@ui, ' docker') 81 | end 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/services/openshift.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | class OpenShift < ServiceBase 4 | PORT = 8443 5 | 6 | def initialize(machine, env) 7 | super(machine, env) 8 | @service_name = 'openshift' 9 | end 10 | 11 | def execute 12 | if service_start_allowed? 13 | command = 'sccli openshift' 14 | command = "#{extra_command_options} #{command}" unless extra_command_options.empty? 15 | command = "#{proxy_cmd_options} #{command}" unless proxy_cmd_options.empty? 16 | 17 | exit_code = PluginUtil.execute_and_exit_on_fail(@machine, @ui, command) 18 | 19 | if exit_code.zero? 20 | @ui.info I18n.t('servicemanager.actions.service_success', service: 'OpenShift') 21 | else 22 | @ui.info I18n.t('servicemanager.actions.service_failure', service: 'OpenShift') 23 | end 24 | end 25 | rescue Vagrant::Errors::GuestCapabilityNotFound 26 | PluginLogger.debug('Guest capability not found while starting OpenShift service') 27 | rescue StandardError => e 28 | @ui.error e.message.squeeze 29 | exit 126 30 | end 31 | 32 | def status 33 | PluginUtil.print_service_status(@ui, @machine, @service_name) 34 | end 35 | 36 | def info(options = {}) 37 | options[:script_readable] ||= false 38 | 39 | if PluginUtil.service_running?(@machine, 'openshift') 40 | options[:url] = "https://#{PluginUtil.machine_ip(@machine)}:#{PORT}" 41 | options[:console_url] = "#{options[:url]}/console" 42 | options[:docker_registry] = docker_registry_host 43 | print_info(options) 44 | else 45 | @ui.error I18n.t('servicemanager.commands.env.service_not_running', 46 | name: 'OpenShift') 47 | exit 126 48 | end 49 | end 50 | 51 | def service_start_allowed? 52 | # openshift to be started by default for CDK 53 | (cdk? && @services.empty?) || @services.include?('openshift') 54 | end 55 | 56 | private 57 | 58 | def extra_command_options 59 | cmd = '' 60 | 61 | OPENSHIFT_CONFIG.each do |key| 62 | unless @machine.config.servicemanager.send(key).nil? 63 | env_name = key.to_s.gsub(/openshift_/, '').upcase 64 | cmd += "#{env_name}='#{@machine.config.servicemanager.send(key)}' " 65 | end 66 | end 67 | 68 | cmd.chop 69 | end 70 | 71 | def print_info(options) 72 | PluginLogger.debug("script_readable: #{options[:script_readable] || false}") 73 | 74 | label = PluginUtil.env_label(options[:script_readable]) 75 | message = I18n.t("servicemanager.commands.env.openshift.#{label}", 76 | openshift_url: options[:url], 77 | openshift_console_url: options[:console_url], 78 | docker_registry: options[:docker_registry]) 79 | @ui.info(message) 80 | 81 | return if options[:script_readable] || options[:all] 82 | PluginUtil.print_shell_configure_info(@ui, ' openshift') 83 | end 84 | 85 | def docker_registry_host 86 | url = '' 87 | PluginLogger.debug 88 | command = \ 89 | 'sudo oc --config=/var/lib/openshift/openshift.local.' \ 90 | 'config/master/admin.kubeconfig get route/docker-registry ' \ 91 | '-o template --template={{.spec.host}}' 92 | 93 | @machine.communicate.execute(command) do |type, data| 94 | url << data.chomp if type == :stdout 95 | end 96 | url 97 | end 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /features/adb-openshift.feature: -------------------------------------------------------------------------------- 1 | Feature: Command output from various OpenShift related commands in ADB 2 | service-manager should return the correct output from commands affecting OpenShift in ADB 3 | 4 | @ci-only 5 | Scenario Outline: Boot and execute commands 6 | Given box is 7 | And provider is 8 | And a file named "Vagrantfile" with: 9 | """ 10 | begin 11 | require 'vagrant-libvirt' 12 | rescue LoadError 13 | # NOOP 14 | end 15 | 16 | Vagrant.configure('2') do |config| 17 | config.vm.box = '' 18 | config.vm.box_url = 'file://../../.boxes/-.box' 19 | config.vm.network :private_network, ip: '' 20 | config.vm.synced_folder '.', '/vagrant', disabled: true 21 | 22 | config.vm.provider('libvirt') { |v| v.memory = 3072 } 23 | config.vm.provider('virtualbox') { |v| v.memory = 3072 } 24 | 25 | config.servicemanager.services = 'openshift' 26 | end 27 | """ 28 | 29 | When I successfully run `bundle exec vagrant up --provider ` 30 | Then stdout from "bundle exec vagrant up --provider " should contain: 31 | """ 32 | ==> default: Docker service configured successfully... 33 | ==> default: OpenShift service configured successfully... 34 | """ 35 | 36 | When I sleep for 10 seconds 37 | And I successfully run `bundle exec vagrant service-manager status` 38 | Then stdout from "bundle exec vagrant service-manager status" should contain "openshift - running" 39 | 40 | When I successfully run `bundle exec vagrant service-manager env openshift` 41 | Then stdout from "bundle exec vagrant service-manager env openshift" should be evaluable in a shell 42 | And stdout from "bundle exec vagrant service-manager env openshift" should contain: 43 | """ 44 | # You can access the OpenShift console on: https://:8443/console 45 | # To use OpenShift CLI, run: oc login https://:8443 46 | export OPENSHIFT_URL=https://:8443 47 | export OPENSHIFT_WEB_CONSOLE=https://:8443/console 48 | export DOCKER_REGISTRY=hub.openshift.centos7-adb..xip.io 49 | 50 | # run following command to configure your shell: 51 | # eval "$(vagrant service-manager env openshift)" 52 | """ 53 | 54 | When I successfully run `bundle exec vagrant service-manager env openshift --script-readable` 55 | Then stdout from "bundle exec vagrant service-manager env openshift --script-readable" should be script readable 56 | And stdout from "bundle exec vagrant service-manager env openshift --script-readable" should contain: 57 | """ 58 | OPENSHIFT_URL=https://:8443 59 | OPENSHIFT_WEB_CONSOLE=https://:8443/console 60 | DOCKER_REGISTRY=hub.openshift.centos7-adb..xip.io 61 | """ 62 | 63 | When I successfully run `bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0` 64 | Then the exit status should be 0 65 | And the binary "oc" of service "openshift" should be installed with version "1.3.0" 66 | And stdout from "bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0" should be evaluable in a shell 67 | 68 | When I evaluate and run `bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0 --path #{ENV['VAGRANT_HOME']}` 69 | Then the exit status should be 0 70 | And the binary should be installed in path "#{ENV['VAGRANT_HOME']}/oc" 71 | And stdout after evaluating and running "bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0 --path #{ENV['VAGRANT_HOME']}" should be evaluable in a shell 72 | 73 | When I successfully run `bundle exec vagrant reload` 74 | And I sleep for 10 seconds 75 | And I successfully run `bundle exec vagrant service-manager status openshift` 76 | Then the exit status should be 0 77 | And the service "openshift" should be running 78 | 79 | Examples: 80 | | box | provider | ip | 81 | | adb | libvirt | 10.10.10.42 | 82 | | adb | virtualbox | 10.10.10.42 | 83 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/installer_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../test_helper' 2 | 3 | module VagrantPlugins 4 | module ServiceManager 5 | describe Installer do 6 | before do 7 | @machine = fake_machine 8 | @ui = FakeUI.new 9 | @machine.env.stubs(:ui).returns(@ui) 10 | 11 | # set test path 12 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 13 | ServiceManager.bin_dir = "#{@plugin_test_path}/bin" 14 | ServiceManager.temp_dir = "#{@plugin_test_path}/temp" 15 | end 16 | 17 | after do 18 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 19 | end 20 | 21 | describe 'Docker' do 22 | before do 23 | @options = { type: :docker, box_version: 'adb', '--cli-version' => '1.11.0' } 24 | @installer = Installer.new(@machine, @machine.env, @options) 25 | end 26 | 27 | it 'should set default values properly' do 28 | @installer.instance_variable_get('@type').must_equal @options[:type] 29 | @installer.instance_variable_get('@machine').must_equal @machine 30 | @installer.instance_variable_get('@env').must_equal @machine.env 31 | @installer.instance_variable_get('@options').must_equal(@options) 32 | end 33 | 34 | it 'should build handler class dynamically' do 35 | @installer.handler_class.must_equal ADBDockerBinaryHandler.to_s 36 | end 37 | 38 | it 'should skip installing if binary path exists' do 39 | # create mock docker binary 40 | bin_folder_path = "#{ServiceManager.bin_dir}/docker/#{@options['--cli-version']}" 41 | FileUtils.mkdir_p(bin_folder_path) 42 | FileUtils.touch("#{bin_folder_path}/docker") 43 | 44 | @installer.instance_variable_get('@binary_handler').binary_exists.must_equal true 45 | end 46 | end 47 | 48 | describe 'OpenShift' do 49 | before do 50 | @options = { type: :openshift, box_version: 'adb', '--cli-version' => '1.2.0' } 51 | @installer = Installer.new(@machine, @machine.env, @options) 52 | end 53 | 54 | it 'should set default values properly' do 55 | @installer.instance_variable_get('@type').must_equal @options[:type] 56 | @installer.instance_variable_get('@machine').must_equal @machine 57 | @installer.instance_variable_get('@env').must_equal @machine.env 58 | @installer.instance_variable_get('@options').must_equal(@options) 59 | end 60 | 61 | it 'should build handler class dynamically' do 62 | @installer.handler_class.must_equal ADBOpenshiftBinaryHandler.to_s 63 | end 64 | 65 | it 'should skip installing if binary path exists' do 66 | # create mock docker binary 67 | bin_folder_path = "#{ServiceManager.bin_dir}/openshift/#{@options['--cli-version']}" 68 | FileUtils.mkdir_p(bin_folder_path) 69 | FileUtils.touch("#{bin_folder_path}/oc") 70 | 71 | @installer.instance_variable_get('@binary_handler').binary_exists.must_equal true 72 | end 73 | end 74 | 75 | describe 'Kubernetes' do 76 | before do 77 | @options = { type: :kubernetes, box_version: 'adb' } 78 | @installer = Installer.new(@machine, @machine.env, @options) 79 | end 80 | 81 | it 'should set default values properly' do 82 | @installer.instance_variable_get('@type').must_equal @options[:type] 83 | @installer.instance_variable_get('@machine').must_equal @machine 84 | @installer.instance_variable_get('@env').must_equal @machine.env 85 | @installer.instance_variable_get('@options').must_equal(@options) 86 | end 87 | 88 | it 'should build handler class dynamically' do 89 | @installer.handler_class.must_equal ADBKubernetesBinaryHandler.to_s 90 | end 91 | 92 | it 'should skip installing if binary path exists' do 93 | # create mock docker binary 94 | bin_folder_path = "#{ServiceManager.bin_dir}/kubernetes/#{@options['--cli-version']}" 95 | FileUtils.mkdir_p(bin_folder_path) 96 | FileUtils.touch("#{bin_folder_path}/kubectl") 97 | 98 | @installer.instance_variable_get('@binary_handler').binary_exists.must_equal true 99 | end 100 | end 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/binary_handlers/adb_kubernetes_binary_handler_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../test_helper' 2 | require 'vagrant/util/downloader' 3 | 4 | # Tests through ADBKubernetesBinaryHandler to BinaryHandler 5 | module VagrantPlugins 6 | module ServiceManager 7 | describe ADBKubernetesBinaryHandler do 8 | before do 9 | @machine = fake_machine 10 | @options = { type: :kubernetes, '--cli-version' => '1.2.0' } # 1.2.0 is available in CDK/ADB VM 11 | @base_download_url = 'https://storage.googleapis.com/kubernetes-release/release' 12 | # set test path 13 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 14 | ServiceManager.temp_dir = "#{@plugin_test_path}/temp" 15 | ServiceManager.bin_dir = "#{@plugin_test_path}/bin" 16 | 17 | @handler = ADBKubernetesBinaryHandler.new(@machine, @machine.env, @options) 18 | end 19 | 20 | after do 21 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 22 | end 23 | 24 | it 'should set defaults values properly' do 25 | @handler.instance_variable_get('@machine').must_equal @machine 26 | @handler.url.must_equal '' 27 | @handler.binary_exists.must_equal true 28 | @handler.skip_download.must_equal false 29 | @handler.archive_file_path.must_equal '' 30 | @handler.type.must_equal @options[:type] 31 | @handler.version.must_equal @options['--cli-version'] 32 | @handler.path.must_equal "#{ServiceManager.bin_dir}/kubernetes/1.2.0/kubectl" 33 | expected_temp_bin_dir = "#{ServiceManager.temp_dir}/kubernetes" 34 | @handler.instance_variable_get('@temp_bin_dir').must_equal expected_temp_bin_dir 35 | end 36 | 37 | it 'should build download url' do 38 | expected_url = @base_download_url + '/v1.2.0/bin/linux/amd64/kubectl' 39 | expected_url.sub!(/linux/, 'darwin') if Vagrant::Util::Platform.darwin? 40 | 41 | @handler.send(:build_download_url) 42 | @handler.instance_variable_get('@url').must_equal expected_url 43 | end 44 | 45 | it 'should validate download url' do 46 | @handler.build_download_url 47 | @handler.validate_url.must_equal true 48 | end 49 | 50 | it 'should raise error with invalid --cli-version' do 51 | @options['--cli-version'] = '111.222.333' 52 | @handler = ADBKubernetesBinaryHandler.new(@machine, @machine.env, @options) 53 | @handler.build_download_url 54 | assert_raises(URLValidationError) { @handler.validate_url } 55 | end 56 | 57 | it 'should build archive path' do 58 | expected_path = "#{ServiceManager.temp_dir}/kubernetes/kubectl" 59 | @handler.build_download_url 60 | @handler.build_archive_path 61 | @handler.instance_variable_get('@archive_file_path').must_equal expected_path 62 | end 63 | 64 | it 'should ensure availability of binary and temp directories' do 65 | expected_bin_dir = "#{ServiceManager.bin_dir}/kubernetes" 66 | expected_temp_dir = "#{ServiceManager.temp_dir}/kubernetes" 67 | 68 | @handler.build_download_url 69 | @handler.build_archive_path 70 | @handler.ensure_binary_and_temp_directories 71 | 72 | assert_equal(File.directory?(expected_bin_dir), true) 73 | assert_equal(File.directory?(expected_temp_dir), true) 74 | end 75 | 76 | it 'should not download if archive file exists' do 77 | archive_file_dir = "#{ServiceManager.temp_dir}/kubernetes" 78 | FileUtils.mkdir_p(archive_file_dir) unless File.directory?(archive_file_dir) 79 | FileUtils.touch("#{archive_file_dir}/kubectl") 80 | 81 | @handler.build_download_url 82 | @handler.build_archive_path 83 | @handler.download_archive 84 | 85 | @handler.skip_download.must_equal true 86 | end 87 | 88 | it 'should prepare binary properly' do 89 | test_archive_path = "#{test_data_dir_path}/kubectl" 90 | 91 | @handler.build_download_url 92 | @handler.build_archive_path 93 | @handler.ensure_binary_and_temp_directories 94 | 95 | FileUtils.cp(test_archive_path, @handler.archive_file_path) 96 | 97 | @handler.prepare_binary 98 | @handler.binary_name.must_equal 'kubectl' 99 | assert_equal(File.exist?(@handler.path), true) 100 | end 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/binary_handlers/adb_openshift_binary_handler_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../test_helper' 2 | require 'vagrant/util/downloader' 3 | 4 | # Tests through ADBOpenshiftBinaryHandler to BinaryHandler 5 | module VagrantPlugins 6 | module ServiceManager 7 | describe ADBOpenshiftBinaryHandler do 8 | before do 9 | @machine = fake_machine 10 | @options = { type: :openshift, '--cli-version' => '1.2.0' } 11 | @archive_base_url = 'https://github.com/openshift/origin/releases/download/v1.2.0' 12 | @archive_file = 'openshift-origin-client-tools-v1.2.0-2e62fab-linux-64bit.tar.gz' 13 | @archive_file.sub!(/linux-64bit.tar.gz/, 'mac.zip') if Vagrant::Util::Platform.darwin? 14 | 15 | # set test path 16 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 17 | ServiceManager.temp_dir = "#{@plugin_test_path}/temp" 18 | ServiceManager.bin_dir = "#{@plugin_test_path}/bin" 19 | 20 | @handler = ADBOpenshiftBinaryHandler.new(@machine, @machine.env, @options) 21 | end 22 | 23 | after do 24 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 25 | end 26 | 27 | it 'should set defaults values properly' do 28 | @handler.instance_variable_get('@machine').must_equal @machine 29 | @handler.url.must_equal '' 30 | @handler.binary_exists.must_equal true 31 | @handler.skip_download.must_equal false 32 | @handler.archive_file_path.must_equal '' 33 | @handler.type.must_equal @options[:type] 34 | @handler.version.must_equal @options['--cli-version'] 35 | @handler.path.must_equal "#{ServiceManager.bin_dir}/openshift/1.2.0/oc" 36 | expected_temp_bin_dir = "#{ServiceManager.temp_dir}/openshift" 37 | @handler.instance_variable_get('@temp_bin_dir').must_equal expected_temp_bin_dir 38 | end 39 | 40 | it 'should build download url' do 41 | expected_url = "#{@archive_base_url}/#{@archive_file}" 42 | 43 | @handler.send(:build_download_url) 44 | @handler.instance_variable_get('@url').must_equal expected_url 45 | end 46 | 47 | it 'should validate download url' do 48 | @handler.build_download_url 49 | @handler.validate_url.must_equal true 50 | end 51 | 52 | it 'should raise error with invalid --cli-version' do 53 | @options['--cli-version'] = '111.222.333' 54 | @handler = ADBDockerBinaryHandler.new(@machine, @machine.env, @options) 55 | @handler.build_download_url 56 | assert_raises(URLValidationError) { @handler.validate_url } 57 | end 58 | 59 | it 'should build archive path' do 60 | expected_path = "#{ServiceManager.temp_dir}/openshift/#{@archive_file}" 61 | 62 | @handler.build_download_url 63 | @handler.build_archive_path 64 | @handler.instance_variable_get('@archive_file_path').must_equal expected_path 65 | end 66 | 67 | it 'should ensure availability of binary and temp directories' do 68 | expected_bin_dir = "#{ServiceManager.bin_dir}/openshift" 69 | expected_temp_dir = "#{ServiceManager.temp_dir}/openshift" 70 | 71 | @handler.build_download_url 72 | @handler.build_archive_path 73 | @handler.ensure_binary_and_temp_directories 74 | 75 | assert_equal(File.directory?(expected_bin_dir), true) 76 | assert_equal(File.directory?(expected_temp_dir), true) 77 | end 78 | 79 | it 'should not download if archive file exists' do 80 | archive_file_dir = "#{ServiceManager.temp_dir}/openshift" 81 | FileUtils.mkdir_p(archive_file_dir) unless File.directory?(archive_file_dir) 82 | FileUtils.touch("#{archive_file_dir}/#{@archive_file}") 83 | 84 | @handler.build_download_url 85 | @handler.build_archive_path 86 | @handler.download_archive 87 | 88 | @handler.skip_download.must_equal true 89 | end 90 | 91 | it 'should prepare binary properly' do 92 | test_archive_path = "#{test_data_dir_path}/#{@archive_file}" 93 | 94 | @handler.build_download_url 95 | @handler.build_archive_path 96 | @handler.ensure_binary_and_temp_directories 97 | 98 | FileUtils.cp(test_archive_path, @handler.archive_file_path) 99 | 100 | @handler.prepare_binary 101 | @handler.binary_name.must_equal 'oc' 102 | @handler.file_regex.must_equal(/oc$/) 103 | if Vagrant::Util::Platform.darwin? 104 | @handler.archive_handler_class.must_equal VagrantPlugins::ServiceManager::ZipHandler 105 | else 106 | @handler.archive_handler_class.must_equal VagrantPlugins::ServiceManager::TarHandler 107 | end 108 | assert_equal(File.exist?(@handler.path), true) 109 | end 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /test/vagrant-service-manager/binary_handlers/adb_docker_binary_handler_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../test_helper' 2 | require 'vagrant/util/downloader' 3 | 4 | # Tests through ADBDockerBinaryHandler to BinaryHandler 5 | module VagrantPlugins 6 | module ServiceManager 7 | describe ADBDockerBinaryHandler do 8 | before do 9 | @machine = fake_machine 10 | @options = { type: :docker, '--cli-version' => '1.11.0' } 11 | 12 | # set test path 13 | @plugin_test_path = "#{@machine.env.data_dir}/service-manager/test" 14 | ServiceManager.temp_dir = "#{@plugin_test_path}/temp" 15 | ServiceManager.bin_dir = "#{@plugin_test_path}/bin" 16 | 17 | @handler = ADBDockerBinaryHandler.new(@machine, @machine.env, @options) 18 | end 19 | 20 | after do 21 | FileUtils.rmtree(@plugin_test_path) if File.directory? @plugin_test_path 22 | end 23 | 24 | it 'should set defaults values properly' do 25 | @handler.instance_variable_get('@machine').must_equal @machine 26 | @handler.url.must_equal '' 27 | @handler.binary_exists.must_equal true 28 | @handler.skip_download.must_equal false 29 | @handler.archive_file_path.must_equal '' 30 | @handler.type.must_equal @options[:type] 31 | @handler.version.must_equal @options['--cli-version'] 32 | @handler.path.must_equal "#{ServiceManager.bin_dir}/docker/1.11.0/docker" 33 | expected_temp_bin_dir = "#{ServiceManager.temp_dir}/docker" 34 | @handler.instance_variable_get('@temp_bin_dir').must_equal expected_temp_bin_dir 35 | end 36 | 37 | it 'should build download url' do 38 | expected_url = 'https://get.docker.com/builds/Linux/x86_64/docker-1.11.0.tgz' 39 | expected_url.sub!(/Linux/, 'Darwin') if Vagrant::Util::Platform.darwin? 40 | 41 | @handler.send(:build_download_url) 42 | @handler.instance_variable_get('@url').must_equal expected_url 43 | end 44 | 45 | # Binary format changed after 1.11.0 46 | # https://github.com/docker/docker/blob/v1.11.0-rc1/CHANGELOG.md#1110-2016-04-12 47 | it 'should build download url for docker < 1.11.0' do 48 | expected_url = 'https://get.docker.com/builds/Linux/x86_64/docker-1.10.3' 49 | expected_url.sub!(/Linux/, 'Darwin') if Vagrant::Util::Platform.darwin? 50 | 51 | @handler.version = '1.10.3' 52 | @handler.build_download_url 53 | @handler.url.must_equal expected_url 54 | end 55 | 56 | it 'should validate download url' do 57 | @handler.build_download_url 58 | @handler.validate_url.must_equal true 59 | end 60 | 61 | it 'should raise error with invalid --cli-version' do 62 | @options['--cli-version'] = '111.222.333' 63 | @handler = ADBDockerBinaryHandler.new(@machine, @machine.env, @options) 64 | @handler.build_download_url 65 | assert_raises(URLValidationError) { @handler.validate_url } 66 | end 67 | 68 | it 'should build archive path' do 69 | expected_path = "#{ServiceManager.temp_dir}/docker/docker-1.11.0.tgz" 70 | @handler.build_download_url 71 | @handler.build_archive_path 72 | @handler.instance_variable_get('@archive_file_path').must_equal expected_path 73 | end 74 | 75 | it 'should ensure availability of binary and temp directories' do 76 | expected_bin_dir = "#{ServiceManager.bin_dir}/docker" 77 | expected_temp_dir = "#{ServiceManager.temp_dir}/docker" 78 | 79 | @handler.build_download_url 80 | @handler.build_archive_path 81 | @handler.ensure_binary_and_temp_directories 82 | 83 | assert_equal(File.directory?(expected_bin_dir), true) 84 | assert_equal(File.directory?(expected_temp_dir), true) 85 | end 86 | 87 | it 'should not download if archive file exists' do 88 | archive_file_dir = "#{ServiceManager.temp_dir}/docker" 89 | FileUtils.mkdir_p(archive_file_dir) unless File.directory?(archive_file_dir) 90 | FileUtils.touch("#{archive_file_dir}/docker-1.11.0.tgz") 91 | 92 | @handler.build_download_url 93 | @handler.build_archive_path 94 | @handler.download_archive 95 | 96 | @handler.skip_download.must_equal true 97 | end 98 | 99 | it 'should prepare binary properly' do 100 | test_archive_path = "#{test_data_dir_path}/docker-1.11.0.tgz" 101 | 102 | @handler.build_download_url 103 | @handler.build_archive_path 104 | @handler.ensure_binary_and_temp_directories 105 | 106 | FileUtils.cp(test_archive_path, @handler.archive_file_path) 107 | 108 | @handler.prepare_binary 109 | @handler.binary_name.must_equal 'docker' 110 | @handler.file_regex.must_equal %r{\/docker$} 111 | @handler.archive_handler_class.must_equal VagrantPlugins::ServiceManager::TarHandler 112 | assert_equal(File.exist?(@handler.path), true) 113 | end 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /features/cdk-openshift.feature: -------------------------------------------------------------------------------- 1 | Feature: Command output from various OpenShift related commands in CDK 2 | service-manager should return the correct output from commands affecting OpenShift in CDK 3 | 4 | @todo 5 | Scenario Outline: Boot and execute commands 6 | Given box is 7 | And provider is 8 | And a file named "Vagrantfile" with: 9 | """ 10 | begin 11 | require 'vagrant-libvirt' 12 | rescue LoadError 13 | # NOOP 14 | end 15 | 16 | Vagrant.configure('2') do |config| 17 | config.vm.box = '' 18 | config.vm.box_url = 'file://../../.boxes/-.box' 19 | config.vm.network :private_network, ip: '' 20 | config.vm.synced_folder '.', '/vagrant', disabled: true 21 | 22 | config.vm.provider('libvirt') { |v| v.memory = 3072 } 23 | config.vm.provider('virtualbox') { |v| v.memory = 3072 } 24 | 25 | config.servicemanager.services = 'openshift' 26 | end 27 | """ 28 | 29 | When I successfully run `bundle exec vagrant up --provider ` 30 | Then stdout from "bundle exec vagrant up --provider " should contain: 31 | """ 32 | ==> default: Docker service configured successfully... 33 | ==> default: OpenShift service configured successfully... 34 | """ 35 | 36 | And I successfully run `bundle exec vagrant service-manager status` 37 | Then stdout from "bundle exec vagrant service-manager status" should contain "openshift - running" 38 | 39 | When I successfully run `bundle exec vagrant service-manager env openshift` 40 | Then stdout from "bundle exec vagrant service-manager env openshift" should be evaluable in a shell 41 | And stdout from "bundle exec vagrant service-manager env openshift" should contain: 42 | """ 43 | # You can access the OpenShift console on: https://:8443/console 44 | # To use OpenShift CLI, run: oc login https://:8443 45 | export OPENSHIFT_URL=https://:8443 46 | export OPENSHIFT_WEB_CONSOLE=https://:8443/console 47 | export DOCKER_REGISTRY=hub.openshift.rhel-cdk..xip.io 48 | 49 | # run following command to configure your shell: 50 | # eval "$(vagrant service-manager env openshift)" 51 | """ 52 | 53 | When I successfully run `bundle exec vagrant service-manager env openshift --script-readable` 54 | Then stdout from "bundle exec vagrant service-manager env openshift --script-readable" should be script readable 55 | And stdout from "bundle exec vagrant service-manager env openshift --script-readable" should contain: 56 | """ 57 | OPENSHIFT_URL=https://:8443 58 | OPENSHIFT_WEB_CONSOLE=https://:8443/console 59 | DOCKER_REGISTRY=hub.openshift.rhel-cdk..xip.io 60 | """ 61 | 62 | When I successfully run `bundle exec vagrant service-manager env` 63 | Then stdout from "bundle exec vagrant service-manager env" should contain "export DOCKER_HOST=tcp://:2376" 64 | And stdout from "bundle exec vagrant service-manager env" should match /export DOCKER_CERT_PATH=.*\/.vagrant\/machines\/cdk\/virtualbox\/docker/ 65 | And stdout from "bundle exec vagrant service-manager env" should contain "export DOCKER_TLS_VERIFY=1" 66 | And stdout from "bundle exec vagrant service-manager env" should match /export DOCKER_API_VERSION=1.2\d/ 67 | And stdout from "bundle exec vagrant service-manager env" should match /# eval "\$\(vagrant service-manager env\)"/ 68 | And stdout from "bundle exec vagrant service-manager env" should contain: 69 | """ 70 | # openshift env: 71 | # You can access the OpenShift console on: https://:8443/console 72 | # To use OpenShift CLI, run: oc login https://:8443 73 | export OPENSHIFT_URL=https://:8443 74 | export OPENSHIFT_WEB_CONSOLE=https://:8443/console 75 | export DOCKER_REGISTRY=hub.openshift.rhel-cdk..xip.io 76 | 77 | # run following command to configure your shell: 78 | # eval "$(vagrant service-manager env)" 79 | """ 80 | 81 | When I run `bundle exec vagrant service-manager install-cli openshift` 82 | Then the exit status should be 0 83 | And the binary "oc" should be installed 84 | 85 | When I run `bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0` 86 | Then the exit status should be 0 87 | And the binary "oc" of service "openshift" should be installed with version "1.3.0" 88 | And stdout from "bundle exec vagrant service-manager install-cli openshift --cli-version 1.3.0" should be evaluable in a shell 89 | 90 | When I evaluate and run `bundle exec vagrant service-manager install-cli openshift --path #{ENV['VAGRANT_HOME']}` 91 | Then the exit status should be 0 92 | And the binary should be installed in path "#{ENV['VAGRANT_HOME']}/oc" 93 | And stdout after evaluating and running "bundle exec vagrant service-manager install-cli openshift --path #{ENV['VAGRANT_HOME']}" should be evaluable in a shell 94 | 95 | When I successfully run `bundle exec vagrant reload` 96 | And I successfully run `bundle exec vagrant service-manager status openshift` 97 | Then the exit status should be 0 98 | And the service "openshift" should be running 99 | 100 | Examples: 101 | | box | provider | ip | 102 | | cdk | virtualbox | 10.10.10.42 | 103 | | cdk | libvirt | 10.10.10.42 | 104 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | = Contributing to vagrant-service-manager 2 | :toc: 3 | :toc-placement!: 4 | 5 | The following is a set of guidelines for contributing to the 6 | vagrant-service-manager plugin. These are guidelines, please use your best 7 | judgment and feel free to propose changes to this document. 8 | 9 | ''' 10 | toc::[] 11 | ''' 12 | 13 | == Submitting issues 14 | 15 | You can submit issues with respect to the vagrant-service-manager plugin 16 | https://github.com/projectatomic/vagrant-service-manager/issues/new[here]. 17 | Make sure you include all the relevant details pertaining the issue. 18 | 19 | Before submitting a new issue, it is suggested to check the 20 | https://github.com/projectatomic/vagrant-service-manager/issues[existing 21 | issues] in order to avoid duplication. The vagrant-service-manager 22 | plugin works closely with the 23 | https://github.com/projectatomic/adb-atomic-developer-bundle/issues[Atomic 24 | Developer Bundle] and the 25 | https://github.com/projectatomic/adb-utils/issues[adb-utils] RPM. You 26 | may wish to review the issues in both these repositories as well. 27 | 28 | == Submitting pull requests 29 | 30 | === Get Started 31 | 32 | If you are just getting started with Git and GitHub there are a few 33 | prerequisite steps. 34 | 35 | * Make sure you have a https://github.com/signup/free[GitHub account]. 36 | * https://help.github.com/articles/fork-a-repo/[Fork] the 37 | vagrant-service-manager repository. As discussed in the linked page, 38 | this also includes: 39 | ** https://help.github.com/articles/set-up-git[Setting up] your local 40 | git install. 41 | ** Cloning your fork. 42 | 43 | === Create a topic branch 44 | 45 | Create a 46 | http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches[topic 47 | branch] on which you will work. The convention is to name the branch 48 | using the issue key you are working on. If there is not already an issue 49 | covering the work you want to do, create one (see 50 | link:#submitting-issues[submitting issues]). Assuming for example you 51 | will be working from the master branch and working on the GitHub issue 52 | 123 : `git checkout -b fix-123 master` 53 | 54 | === Code 55 | 56 | Do your work! Refer to the link:README.adoc#development[development] 57 | section in the link:README.adoc[README] to get started. 58 | 59 | === Commit 60 | 61 | * Make commits of logical units. 62 | * Be sure to use the GitHub issue key in the commit message, eg `Fix #123 ...`. 63 | * Make sure your code conforms to the coding style 64 | * Make sure you have added the necessary tests for your changes. 65 | * Make sure you have added appropriate documentation updates. 66 | * Run _all_ the tests to assure nothing else was accidentally broken. 67 | 68 | === Submit 69 | 70 | * Push your changes to the topic branch in your fork of the repository. 71 | * Initiate a https://help.github.com/articles/using-pull-requests/[pull 72 | request]. 73 | * All changes need at least 2 ACKs from maintainers before they will be 74 | merged. If the author of the PR is a maintainer, their submission is 75 | considered to be the first ACK. Therefore, pull requests from 76 | maintainers only need one additional ACK. By "2 ACKs" we mean that two 77 | maintainers must acknowledge that the change is a good one. 78 | 79 | == Merging pull requests 80 | 81 | A project maintainer will merge the pull request. He should avoid using 82 | the GitHub UI for the merge and prefer merges over the the command line 83 | to avoid merge commits and to keep a linear commit history. Here is an 84 | example work-flow assuming issue 123 from above: 85 | 86 | ------------------------------------------------------------------------- 87 | # Create a local branch for the pull request 88 | $ git checkout -b fix-123 master 89 | 90 | # Pull the changes 91 | $ git pull fix-123 92 | 93 | # If necessary rebase changes on master to ensure we have a fast forward. 94 | $ git rebase -i master 95 | 96 | # If required, update CHANGELOG.md in the unreleased section. Commit! 97 | 98 | # Merge changes into master 99 | $ git checkout master 100 | $ git merge fix-123 101 | 102 | # Push to origin 103 | $ git push origin master 104 | ------------------------------------------------------------------------- 105 | 106 | == Releasing 107 | 108 | * Make sure the HEAD of development builds and passes all tests: 109 | `bundle exec rake clean rubocop test features install`. You can also 110 | verify against https://ci.centos.org/job/vagrant-service-manager[CI] 111 | * Review https://github.com/projectatomic/vagrant-service-manager/milestones[milestone] for the current release 112 | ** Make sure all issues are resolved 113 | ** Move unresolved issues into an upcoming release 114 | ** Close milestone 115 | * Update the link:CHANGELOG.adoc[CHANGELOG] 116 | * Update link:lib/vagrant-service-manager/version.rb[version.rb] with the correct 117 | release version. Consider http://semver.org/:[Semantic Versioning] guidelines 118 | when deciding on the release version 119 | * Commit _CHANGELOG_ and _version.rb_ using commit message of the form: 120 | `vagrant-service-manager version=` 121 | * Push commit to upstream 122 | * Release the gem: `bundle exec rake release` 123 | * Create a Github https://github.com/projectatomic/vagrant-service-manager/releases[release] and paste change log for release 124 | * Update link:lib/vagrant-service-manager/version.rb[version.rb] with the next anticipated release version, eg _1.42.0.dev_ 125 | * Commit with message: `vagrant-service-manager setting dev version .dev` 126 | * Push upstream 127 | 128 | == Maintainers 129 | 130 | * Brian Exelbierd @bexelbie 131 | * Budh Ram Gurung @budhrg 132 | * Hardy Ferentschik @hferentschik 133 | * Lalatendu Mohanty @LalatenduMohanty 134 | * Navid Shaikh @navidshaikh 135 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/plugin_util.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module ServiceManager 3 | module PluginUtil 4 | def self.service_class(service) 5 | SERVICES_MAP[service] 6 | end 7 | 8 | def self.copy_certs_to_host(machine, path, ui, commented_message = false) 9 | Dir.mkdir(path) unless Dir.exist?(path) 10 | 11 | # Copy the required client side certs from inside the box to host machine 12 | message = "Copying TLS certificates to #{path}" 13 | message = '# ' + message.to_s if commented_message 14 | ui.info(message) 15 | machine.communicate.download("#{DOCKER_PATH}/ca.pem", path.to_s) 16 | machine.communicate.download("#{DOCKER_PATH}/cert.pem", path.to_s) 17 | machine.communicate.download("#{DOCKER_PATH}/key.pem", path.to_s) 18 | end 19 | 20 | def self.generate_kubeconfig(machine, ui, plugin_dir) 21 | FileUtils.mkdir_p(plugin_dir) unless File.directory?(plugin_dir) 22 | File.open("#{plugin_dir}/kubeconfig", 'w') do |config_file| 23 | config_file.write(I18n.t('servicemanager.kube_config', 24 | ip: PluginUtil.machine_ip(machine), 25 | token: service_token(machine, ui))) 26 | end 27 | end 28 | 29 | def self.service_token(machine, ui) 30 | token_template = '-o template --template="{{(index .secrets 0).name}}"' 31 | secret_template = '-o template --template="{{.data.token}}"' 32 | secret_name_cmd = "$(kubectl get serviceaccounts default #{token_template})" 33 | 34 | cmd = "kubectl get secret #{secret_name_cmd} #{secret_template} | base64 -d" 35 | execute_once(machine, ui, cmd) 36 | end 37 | 38 | def self.host_docker_path(machine) 39 | # Path to the private_key and where we will store the TLS Certificates 40 | File.expand_path('docker', machine.data_dir) 41 | end 42 | 43 | def self.machine_ip(machine) 44 | machine.guest.capability(:machine_ip) 45 | end 46 | 47 | def self.sha_id(file_data) 48 | Digest::SHA256.hexdigest file_data 49 | end 50 | 51 | def self.certs_present_and_valid?(path, machine) 52 | return false if Dir["#{path}/*"].empty? 53 | 54 | # check validity of certs 55 | Dir[path + '/*'].each do |f| 56 | guest_file_path = "#{DOCKER_PATH}/#{File.basename(f)}" 57 | guest_sha = machine.guest.capability(:sha_id, guest_file_path) 58 | return false if sha_id(File.read(f)) != guest_sha 59 | end 60 | 61 | true 62 | end 63 | 64 | def self.print_service_status(ui, machine, service) 65 | status = I18n.t('servicemanager.commands.status.status.stopped') 66 | if service_running?(machine, service) 67 | status = I18n.t('servicemanager.commands.status.status.running') 68 | end 69 | ui.info("#{service} - #{status}") 70 | end 71 | 72 | # If 'class' option is true then return the class name of running services 73 | def self.running_services(machine, options = {}) 74 | running_services = [] 75 | 76 | SUPPORTED_SERVICES.each do |service| 77 | next unless service_running?(machine, service) 78 | running_services << (options[:class] ? SERVICES_MAP[service] : service) 79 | end 80 | running_services 81 | end 82 | 83 | def self.service_running?(machine, service) 84 | command = "sudo sccli #{service} status" 85 | machine.communicate.test(command) 86 | end 87 | 88 | def self.windows_path(path) 89 | # Replace / with \ for path in Windows 90 | path.split('/').join('\\') + '\\' 91 | end 92 | 93 | def self.execute_and_exit_on_fail(machine, ui, command) 94 | errors = [] 95 | logged = false # Log one time only 96 | 97 | exit_code = machine.communicate.sudo(command) do |type, data| 98 | PluginLogger.debug unless logged 99 | errors << data if type == :stderr 100 | logged = true 101 | end 102 | 103 | unless exit_code.zero? 104 | ui.error errors.join("\n") 105 | PluginLogger.debug("#{command} exited with code #{exit_code}") 106 | exit exit_code 107 | end 108 | 109 | exit_code 110 | end 111 | 112 | def self.execute_once(machine, ui, command) 113 | machine.communicate.sudo(command) do |_, data| 114 | PluginLogger.debug 115 | return data.chomp 116 | end 117 | rescue StandardError => e 118 | ui.error e.message.squeeze 119 | end 120 | 121 | def self.print_shell_configure_info(ui, command = '') 122 | label = if !Vagrant::Util::Platform.windows? 123 | 'unix_configure_info' 124 | elsif Vagrant::Util::Platform.cygwin? 125 | 'windows_cygwin_configure_info' 126 | end 127 | 128 | ui.info "\n" + I18n.t("servicemanager.commands.env.#{label}", command: command) unless label.nil? 129 | end 130 | 131 | def self.env_label(script_readable) 132 | if script_readable 133 | 'script_readable' 134 | elsif !Vagrant::Util::Platform.windows? 135 | 'non_windows' 136 | elsif Vagrant::Util::Platform.cygwin? 137 | 'windows_cygwin' 138 | else 139 | 'windows' 140 | end 141 | end 142 | 143 | def self.binary_downloaded?(path) 144 | File.file?(path) 145 | end 146 | 147 | def self.format_path(path) 148 | if Vagrant::Util::Platform.cygwin? 149 | Vagrant::Util::Platform.cygwin_path(path) 150 | elsif Vagrant::Util::Platform.windows? 151 | windows_path(path).chop 152 | else 153 | path 154 | end 155 | end 156 | 157 | # special case for oc binary in windows 158 | def self.fetch_existing_oc_binary_path_in_windows 159 | separator = ';' 160 | path_string = ENV['PATH'] 161 | 162 | separator = ':' unless path_string.include?(';') 163 | oc_path_dir = path_string.split(separator).detect do |dir_path| 164 | File.exist? "#{dir_path}\\oc.exe" 165 | end 166 | 167 | oc_path_dir.nil? ? nil : oc_path_dir + '\oc.exe' 168 | end 169 | end 170 | end 171 | end 172 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/binary_handlers/binary_handler.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | 3 | module VagrantPlugins 4 | module ServiceManager 5 | class URLValidationError < Vagrant::Errors::VagrantError 6 | error_key(:url_validation_error) 7 | end 8 | 9 | class BinaryHandler 10 | BINARY_ARCHIVE_FORMATS = ['.tgz', '.tar.gz', '.gz', '.zip'].freeze 11 | BINARY_NAME = { 12 | docker: 'docker', openshift: 'oc', kubernetes: 'kubectl' 13 | }.freeze 14 | VERSION_CMD = { 15 | docker: "docker version --format '{{.Server.Version}}'", 16 | openshift: "oc version | grep -oE 'oc v([0-9a-z.]+-?[a-z0-9]*.?[0-9])' | sed -E 's/oc v//'", 17 | kubernetes: %q(kubectl version --client | sed -E 's/(.*)v([0-9a-z.]+-?[a-z0-9]*.?[0-9]*)",(.*)/\2/') 18 | }.freeze 19 | BINARY_REGEX = { 20 | windows: { docker: %r{\/docker.exe$}, openshift: /oc.exe$/ }, 21 | unix: { docker: %r{\/docker$}, openshift: /oc$/ } 22 | }.freeze 23 | ARCHIVE_MAP = { 24 | '.tgz' => 'Tar', '.tar.gz' => 'Tar', '.gz' => 'Tar', '.zip' => 'Zip' 25 | }.freeze 26 | LABEL = 'servicemanager.commands.install_cli.message'.freeze 27 | 28 | attr_accessor :path, :version, :type, :url, 29 | :binary_exists, :skip_download, :archive_file_path 30 | 31 | def initialize(machine, env, options) 32 | @machine = machine 33 | @ui = env.ui 34 | @url = '' 35 | @binary_exists = true 36 | @skip_download = false 37 | @archive_file_path = '' 38 | @options = options 39 | @args = { insecure: false } 40 | @type = options[:type] 41 | @version = options['--cli-version'] || PluginUtil.execute_once(@machine, @ui, VERSION_CMD[@type]) 42 | @path = options['--path'] ? "#{options['--path']}/#{binary_name}" : binary_path 43 | @temp_bin_dir = "#{ServiceManager.temp_dir}/#{@type}" 44 | end 45 | 46 | def install 47 | build_download_url 48 | validate_url 49 | build_archive_path 50 | ensure_binary_and_temp_directories 51 | download_archive 52 | prepare_binary 53 | end 54 | 55 | def build_archive_path 56 | @archive_file_path = "#{@temp_bin_dir}/#{File.basename(@url)}" 57 | end 58 | 59 | def ensure_binary_and_temp_directories 60 | FileUtils.mkdir_p(bin_dir) unless File.directory?(bin_dir) 61 | FileUtils.mkdir_p(@temp_bin_dir) unless File.directory?(@temp_bin_dir) 62 | end 63 | 64 | def download_archive 65 | return @skip_download = true if File.exist?(@archive_file_path) 66 | set_proxy_environment 67 | @args[:insecure] = true if ENV.key?('CURL_INSECURE') && ENV['CURL_INSECURE'] == 'true' 68 | Vagrant::Util::Downloader.new(@url, @archive_file_path, @args).download! 69 | rescue Vagrant::Errors::DownloaderError => e 70 | @ui.error e.message 71 | exit 126 72 | end 73 | 74 | def prepare_binary 75 | tmp_binary_file_path = @archive_file_path 76 | 77 | # If binary is in archive format, extract it 78 | if binary_archived? 79 | tmp_binary_file_path = "#{archive_dir_name}/#{binary_name}" 80 | unless File.file? tmp_binary_file_path 81 | archive_handler_class.new(@archive_file_path, tmp_binary_file_path, file_regex).unpack 82 | end 83 | end 84 | 85 | FileUtils.cp(tmp_binary_file_path, @path) 86 | File.chmod(0o755, @path) 87 | rescue StandardError => e 88 | @ui.error e.message 89 | exit 126 90 | end 91 | 92 | def print_message(options_msg) 93 | bin_path = PluginUtil.format_path(@path) 94 | @ui.info I18n.t(LABEL, 95 | path: bin_path, dir: File.dirname(bin_path), service: @type, options: options_msg, 96 | binary: binary_name, when: (@binary_exists ? 'already' : 'now')) 97 | end 98 | 99 | def handle_windows_binary_path 100 | return if @type != :openshift 101 | 102 | if @options[:box_version] == 'cdk' 103 | oc_version = CDKOpenshiftBinaryHandler::LATEST_OC_VERSION 104 | end 105 | 106 | return if @options['--cli-version'] != oc_version || @options['--path'] 107 | path = PluginUtil.fetch_existing_oc_binary_path_in_windows 108 | @path = path unless path.nil? 109 | end 110 | 111 | def archive_dir_name 112 | @archive_file_path.sub(Regexp.new(BINARY_ARCHIVE_FORMATS.join('|')), '') 113 | end 114 | 115 | def archive_handler_class 116 | Object.const_get("#{ServiceManager.name}::#{archive_handler_name}") 117 | end 118 | 119 | def binary_name 120 | BINARY_NAME[@type] + binary_ext 121 | end 122 | 123 | def binary_ext 124 | Vagrant::Util::Platform.windows? ? '.exe' : '' 125 | end 126 | 127 | def bin_dir 128 | File.dirname(@path) 129 | end 130 | 131 | def file_regex 132 | os_type = Vagrant::Util::Platform.windows? ? :windows : :unix 133 | BINARY_REGEX[os_type][@type] 134 | end 135 | 136 | # Checks if url is accessible or not 137 | def validate_url 138 | url = URI.parse(@url) 139 | req = Net::HTTP.new(url.host, url.port) 140 | req.use_ssl = true if url.scheme == 'https' 141 | res = req.request_head(url.path) 142 | 143 | unless %w(200 302).include? res.code 144 | raise URLValidationError, I18n.t('servicemanager.commands.install_cli.url_validation_error') 145 | end 146 | 147 | true 148 | end 149 | 150 | private 151 | 152 | def set_proxy_environment 153 | return if @machine.config.servicemanager.proxy.nil? 154 | 155 | env_proxy = @machine.config.servicemanager.proxy 156 | if @machine.config.servicemanager.proxy_user 157 | user = @machine.config.servicemanager.proxy_user 158 | password = @machine.config.servicemanager.proxy_password 159 | env_proxy = env_proxy.sub(%r{(https?:\/\/)*}, "\\1#{user}:#{password}@") 160 | end 161 | 162 | # Net::HTTP will automatically create a proxy from the http_proxy environment variable if present 163 | # More info here http://stackoverflow.com/a/23778707/1120530 164 | ENV['https_proxy'] = env_proxy 165 | end 166 | 167 | def binary_archived? 168 | BINARY_ARCHIVE_FORMATS.include? File.extname(@archive_file_path) 169 | end 170 | 171 | def archive_handler_name 172 | ARCHIVE_MAP[File.extname(@url)] + 'Handler' 173 | end 174 | 175 | def binary_path 176 | "#{ServiceManager.bin_dir}/#{@type}/#{@version}/#{binary_name}" 177 | end 178 | end 179 | end 180 | end 181 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'aruba/cucumber' 2 | require 'komenda' 3 | require 'find' 4 | 5 | ############################################################################### 6 | # Aruba config and Cucumber hooks 7 | ############################################################################### 8 | Aruba.configure do |config| 9 | config.exit_timeout = 3600 10 | config.activate_announcer_on_command_failure = [:stdout, :stderr] 11 | config.working_directory = 'build/aruba' 12 | end 13 | 14 | Before do |scenario| 15 | @scenario_name = scenario.name 16 | ENV['VAGRANT_HOME'] = File.join(File.dirname(__FILE__), '..', '..', 'build', 'vagrant.d') 17 | end 18 | 19 | After do |_scenario| 20 | if File.exist?(File.join(aruba.config.working_directory, 'Vagrantfile')) 21 | Komenda.run('bundle exec vagrant destroy -f', cwd: aruba.config.working_directory, fail_on_fail: true) 22 | if ENV.key?('CUCUMBER_RUN_PROVIDER') 23 | # if we have more than one provider we need to wait between scenarios in order to allow for 24 | # proper cleanup/shutdown of virtualization framework 25 | sleep 10 26 | end 27 | end 28 | 29 | # Remove the created Vagrant home dir 30 | FileUtils.rmtree(ENV['VAGRANT_HOME']) if File.directory? ENV['VAGRANT_HOME'] 31 | end 32 | 33 | ############################################################################### 34 | # Some helper functions 35 | ############################################################################### 36 | # When running Vagrant from within a plugin development environment, Vagrant 37 | # prints a warning which we can ignore 38 | def stdout_without_plugin_context(raw_stdout) 39 | raw_stdout.lines.to_a[6..-1].join 40 | end 41 | 42 | def output_is_evaluable(raw_stdout) 43 | console_out = stdout_without_plugin_context(raw_stdout) 44 | console_out.each_line do |line| 45 | expect(line).to match(/^#.*|^export [a-zA-Z_]+=.*|^\n/) 46 | end 47 | end 48 | 49 | def output_is_script_readable(raw_stdout) 50 | console_out = stdout_without_plugin_context(raw_stdout) 51 | console_out.each_line do |line| 52 | expect(line).to match(/^[a-zA-Z_]+=.*$/) 53 | end 54 | end 55 | 56 | def extract_process_id(data) 57 | tokens = data.scan(/Main PID: ([0-9]+) \(/) 58 | tokens.last.first.to_i unless tokens.empty? 59 | end 60 | 61 | ############################################################################### 62 | # Some shared step definitions 63 | ############################################################################## 64 | Given(/provider is (.*)/) do |current_provider| 65 | requested_provider = ENV.key?('PROVIDER') ? ENV['PROVIDER'] : 'virtualbox' 66 | 67 | unless requested_provider.include?(current_provider) 68 | # puts "Skipping scenario '#{@scenario_name}' for provider '#{current_provider}', since this 69 | # provider is not explicitly enabled via environment variable 'PROVIDER'" 70 | skip_this_scenario 71 | end 72 | end 73 | 74 | Given(/box is (.*)/) do |current_box| 75 | requested_box = ENV.key?('BOX') ? ENV['BOX'] : 'adb' 76 | 77 | unless requested_box.include?(current_box) 78 | # puts "Skipping scenario '#{@scenario_name}' for box '#{current_box}', since this box is not explicitly 79 | # enabled via environment variable 'BOX'" 80 | skip_this_scenario 81 | end 82 | end 83 | 84 | Then(/^stdout from "([^"]*)" should be evaluable in a shell$/) do |cmd| 85 | output_is_evaluable(aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stdout)) 86 | end 87 | 88 | Then(/^stdout after evaluating and running "([^"]*)" should be evaluable in a shell$/) do |cmd| 89 | cmd = sanitize_text(eval('"' + cmd + '"')) 90 | output_is_evaluable(aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stdout)) 91 | end 92 | 93 | Then(/^stdout from "([^"]*)" should be script readable$/) do |cmd| 94 | output_is_script_readable(aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stdout)) 95 | end 96 | 97 | Then(%r{^stdout from "([^"]*)" should match /(.*)/$}) do |cmd, regexp| 98 | aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stdout) =~ /#{regexp}/ 99 | end 100 | 101 | Then(%r{^stderr from evaluating and running "([^"]*)" should match /(.*)/$}) do |cmd, regexp| 102 | cmd = sanitize_text(eval('"' + cmd + '"')) 103 | regexp = sanitize_text(eval('"' + regexp + '"')) 104 | aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stderr) =~ /#{regexp}/ 105 | end 106 | 107 | # track service process ID 108 | @service_current_process_id = -1 109 | 110 | # Note: Only for services supported through systemctl. Not for 'kubernetes'. 111 | Then(/^the service "([^"]*)" should be ([^"]*)$/) do |service, operation| 112 | run("vagrant ssh -c \"sudo systemctl status #{service}\"") 113 | 114 | if %w(running restarted).include? operation 115 | exit_code = 0 116 | regexp = /Active: active \(running\)/ 117 | elsif operation == 'stopped' 118 | exit_code = 3 119 | regexp = /Active: inactive\(dead\)/ 120 | end 121 | 122 | expect(last_command_started).to have_exit_status(exit_code) 123 | aruba.command_monitor.find(Aruba.platform.detect_ruby(last_command_started)).send(:stdout) =~ regexp 124 | end 125 | 126 | # Note: Only for services supported through systemctl. Not for 'kubernetes'. 127 | When(/^the "([^"]*)" service is( not)? running$/) do |service, negated| 128 | run("vagrant ssh -c \"sudo systemctl status #{service}\"") 129 | 130 | if negated 131 | expect(last_command_started).to have_exit_status(3) 132 | else 133 | expect(last_command_started).to have_exit_status(0) 134 | stdout = aruba.command_monitor.find(Aruba.platform.detect_ruby(last_command_started)).send(:stdout) 135 | @service_current_process_id = extract_process_id(stdout) 136 | end 137 | end 138 | 139 | # Note: Only for services supported through systemctl. Not for 'kubernetes'. 140 | When(/^the "([^"]*)" service is \*not\* running$/) do |service| 141 | # Stop the service 142 | run("vagrant ssh -c \"sudo systemctl stop #{service}\"") 143 | 144 | expect(last_command_started).to have_exit_status(0) 145 | step 'the "docker" service is not running' 146 | end 147 | 148 | # Note: Only for services supported through systemctl. Not for 'kubernetes'. 149 | Then(/^have a new pid for "([^"]*)" service$/) do |service| 150 | run("vagrant ssh -c \"sudo systemctl status #{service}\"") 151 | 152 | expect(last_command_started).to have_exit_status(0) 153 | stdout = aruba.command_monitor.find(Aruba.platform.detect_ruby(last_command_started)).send(:stdout) 154 | expect(@service_current_process_id).not_to eq(extract_process_id(stdout)) 155 | end 156 | 157 | Then(/^the binary "([^"]*)" should be installed$/) do |binary| 158 | binaries = [] 159 | Find.find("#{ENV['VAGRANT_HOME']}/data/service-manager/bin") do |path| 160 | binaries << path if path =~ %r{.*\/#{Regexp.quote(binary)}$} && File.file?(path) 161 | end 162 | 163 | expect(binaries.size).to eq(1) 164 | expect(File.executable?(binaries.first)).to eq(true) 165 | end 166 | 167 | Then(/^the binary "([^"]*)" of service "([^"]*)" should be installed with version "([^"]*)"$/) do |b, s, v| 168 | binary_path = "#{ENV['VAGRANT_HOME']}/data/service-manager/bin/#{s}/#{v}/#{b}" 169 | expect(File.file?(binary_path)).to eq(true) 170 | expect(File.executable?(binary_path)).to eq(true) 171 | end 172 | 173 | Then(/^the binary should be installed in path "([^"]*)"$/) do |path| 174 | binary_path = eval('"' + path + '"') 175 | expect(File.file?(binary_path)).to eq(true) 176 | expect(File.executable?(binary_path)).to eq(true) 177 | end 178 | 179 | # Per default the built-in Aruba 'When I run' will not evaluate/interpolate the string. 180 | # We create a custom step definition to work around this 181 | When(/^I evaluate and run `([^`]*)`$/) do |cmd| 182 | cmd = eval('"' + cmd + '"') 183 | cmd = sanitize_text(cmd) 184 | run_simple(cmd, fail_on_error: false) 185 | end 186 | 187 | When(/^I sleep for (\d+) seconds$/) do |time| 188 | sleep(time.to_i) 189 | end 190 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/clean' 3 | require 'rake/testtask' 4 | require 'cucumber/rake/task' 5 | require 'rubocop/rake_task' 6 | require 'mechanize' 7 | require 'fileutils' 8 | require 'yaml' 9 | require 'launchy' 10 | require 'date' 11 | require 'asciidoctor' 12 | 13 | CLOBBER.include('pkg') 14 | CLEAN.include('build') 15 | 16 | BOX_DIR = '.boxes'.freeze 17 | 18 | task :init do 19 | FileUtils.mkdir_p 'build' 20 | end 21 | 22 | desc 'Removes all cached box files' 23 | task :clean_boxes do 24 | FileUtils.rmtree '.boxes' 25 | end 26 | 27 | RuboCop::RakeTask.new 28 | 29 | # Default unit test task 30 | desc 'Run all unit tests' 31 | Rake::TestTask.new do |t| 32 | t.pattern = 'test/**/*_test.rb' 33 | t.libs << 'test' 34 | end 35 | 36 | # Cucumber acceptance test tasks 37 | Cucumber::Rake::Task.new(:features) 38 | task features: [:clean, :init, :get_boxes] 39 | 40 | namespace :features do 41 | desc 'Opens the HTML Cucumber test report' 42 | task :open_report do 43 | Launchy.open('./build/features_report.html') 44 | end 45 | end 46 | 47 | desc 'Render Asciidoc into HTML' 48 | adoc_files = Rake::FileList['**/*.adoc'] 49 | task html: adoc_files.ext('.html') 50 | rule '.html' => '.adoc' do |t| 51 | FileUtils.mkdir_p 'build/html' 52 | Asciidoctor.convert_file t.source, to_dir: 'build/html' 53 | end 54 | 55 | desc 'Download the required Vagrant boxes for the Cucumber tests' 56 | task get_boxes: :init do 57 | box_dir = File.join(File.dirname(__FILE__), BOX_DIR) 58 | 59 | requested_providers = ENV.key?('PROVIDER') ? ENV['PROVIDER'].split(',').collect(&:strip) : ['virtualbox'] 60 | requested_boxes = ENV.key?('BOX') ? ENV['BOX'].split(',').collect(&:strip) : ['adb'] 61 | nightly_cdk_builds = ENV.key?('NIGHTLY') ? ENV['NIGHTLY'].eql?('true') : false 62 | 63 | download_tasks = requested_boxes.map do |box| 64 | requested_providers.map do |provider| 65 | case box 66 | when 'cdk' 67 | if nightly_cdk_builds 68 | NightlyCDKDownloader.new(box_dir, provider) 69 | else 70 | PublicCDKDownloader.new(box_dir, provider) 71 | end 72 | when 'adb' 73 | ADBDownloader.new(box_dir, provider) 74 | else 75 | raise "Unknown provider #{provider}" 76 | end 77 | end 78 | end.flatten! 79 | 80 | threads = download_tasks.map do |task| 81 | Thread.new do 82 | task.execute 83 | end 84 | end 85 | 86 | while threads.any?(&:alive?) 87 | pinwheel = %w(| / - \\) 88 | 4.times do 89 | print "\b" + pinwheel.rotate!.first 90 | sleep(0.3) 91 | end 92 | end 93 | end 94 | 95 | # Helper classes for handling of Vagrant box downloading 96 | class DownloadTask 97 | attr_reader :provider 98 | attr_reader :box_dir 99 | attr_reader :agent 100 | attr_reader :meta 101 | 102 | def initialize(box_dir, provider) 103 | FileUtils.mkdir_p(box_dir) unless File.directory?(box_dir) 104 | @box_dir = box_dir 105 | @provider = provider 106 | 107 | @meta_file_name = File.join(box_dir, "#{name}-#{provider}.yml") 108 | @meta = read_meta 109 | 110 | @agent = Mechanize.new 111 | @agent.follow_meta_refresh = true 112 | @agent.ignore_bad_chunking = true 113 | end 114 | 115 | def needed? 116 | true 117 | end 118 | 119 | def execute 120 | download if needed? 121 | end 122 | 123 | def download 124 | end 125 | 126 | def name 127 | raise 'Needs to be overridden' 128 | end 129 | 130 | def box_file 131 | File.join(box_dir, "#{name}-#{provider}.box") 132 | end 133 | 134 | def read_meta 135 | if File.exist?(@meta_file_name) 136 | YAML.load_file(@meta_file_name) 137 | else 138 | {} 139 | end 140 | end 141 | 142 | def save_meta 143 | File.open(@meta_file_name, 'w+') do |file| 144 | file.write(meta.to_yaml) 145 | end 146 | end 147 | end 148 | 149 | class ADBDownloader < DownloadTask 150 | ADB_DOWNLOAD_URL = 'http://cloud.centos.org/centos/7/atomic/images'.freeze 151 | ADB_BOX_BASE_NAME = 'AtomicDeveloperBundle'.freeze 152 | 153 | def initialize(box_dir, provider) 154 | super(box_dir, provider) 155 | end 156 | 157 | def needed? 158 | latest_version = versions[-1] 159 | if meta.fetch(:current_version, nil).eql?(latest_version) && File.file?(box_file) 160 | puts "Using existing ADB box (version #{latest_version}) in #{box_dir}" 161 | return false 162 | else 163 | File.delete(box_file) if File.exist?(box_file) 164 | meta[:current_version] = latest_version 165 | save_meta 166 | true 167 | end 168 | end 169 | 170 | def download 171 | agent.get(ADB_DOWNLOAD_URL) do |page| 172 | page.links.each do |link| 173 | next unless link.href =~ /#{Regexp.quote(ADB_BOX_BASE_NAME)}-#{Regexp.quote(@meta[:current_version])}-CentOS7-#{Regexp.quote(provider)}.box/i 174 | agent.pluggable_parser.default = Mechanize::Download 175 | puts "Downloading ADB box #{ADB_DOWNLOAD_URL}/#{link.href}" 176 | agent.get(link.href).save(box_file) 177 | end 178 | end 179 | end 180 | 181 | def name 182 | 'adb' 183 | end 184 | 185 | private 186 | 187 | def versions 188 | agent.get(ADB_DOWNLOAD_URL) do |page| 189 | return page.links.select { |link| link.href =~ /#{Regexp.quote(ADB_BOX_BASE_NAME)}.*/ } 190 | .map { |link| link.href.match(/^.*-(\d+\.\d+.\d+)-.*/i).captures[0] } 191 | .uniq 192 | .sort 193 | end 194 | end 195 | end 196 | 197 | class NightlyCDKDownloader < DownloadTask 198 | CDK_DOWNLOAD_URL_NIGHTLY = 'http://cdk-builds.usersys.redhat.com/builds/nightly'.freeze 199 | 200 | def initialize(box_dir, provider) 201 | super(box_dir, provider) 202 | end 203 | 204 | def needed? 205 | latest_version = versions[-1] 206 | if meta.fetch(:current_version, nil).eql?(latest_version) && File.file?(box_file) 207 | puts "Using existing CDK box (from #{latest_version}) in #{box_dir}" 208 | return false 209 | else 210 | File.delete(box_file) if File.exist?(box_file) 211 | meta[:current_version] = latest_version 212 | save_meta 213 | true 214 | end 215 | end 216 | 217 | def download 218 | download_base_url = "#{CDK_DOWNLOAD_URL_NIGHTLY}/#{meta[:current_version]}" 219 | agent.get(download_base_url) do |page| 220 | page.links.each do |link| 221 | next unless link.href =~ /.*#{Regexp.quote(provider)}.box$/ 222 | agent.pluggable_parser.default = Mechanize::Download 223 | puts "Downloading #{download_base_url}/#{link.href}" 224 | agent.get(link.href).save(box_file) 225 | end 226 | end 227 | end 228 | 229 | def name 230 | 'cdk' 231 | end 232 | 233 | private 234 | 235 | def versions 236 | agent.get(CDK_DOWNLOAD_URL_NIGHTLY) do |page| 237 | return page.links.select { |link| link.href =~ /\d{1,2}-[a-zA-Z]{3}-\d{4}/ } 238 | .map { |link| link.href.chomp('/') } 239 | .sort { |a, b| DateTime.strptime(a, '%d-%b-%Y') <=> DateTime.strptime(b, '%d-%b-%Y') } 240 | end 241 | end 242 | end 243 | 244 | class PublicCDKDownloader < DownloadTask 245 | CDK_DOWNLOAD_URL = 'https://access.redhat.com/downloads/content/293/ver=2.2/rhel---7/2.2.0/x86_64/product-software'.freeze 246 | CDK_BOX_BASE_NAME = 'rhel-cdk-kubernetes-7.2-29.x86_64.vagrant'.freeze 247 | LATEST_VERSION = 'v. 2.2.0 for x86_64'.freeze 248 | 249 | def initialize(box_dir, provider) 250 | super(box_dir, provider) 251 | end 252 | 253 | def needed? 254 | if meta.fetch(:current_version, nil).eql?(LATEST_VERSION) && File.file?(box_file) 255 | puts "Using existing public releaase CDK box (version #{LATEST_VERSION}) in #{box_dir}" 256 | false 257 | else 258 | File.delete(box_file) if File.exist?(box_file) 259 | meta[:current_version] = LATEST_VERSION 260 | save_meta 261 | true 262 | end 263 | end 264 | 265 | def download 266 | agent.get(CDK_DOWNLOAD_URL) do |page| 267 | # Submit first form which is the redirect to login page form 268 | login_page = page.forms.first.submit 269 | 270 | # Submit the login form 271 | after_login = login_page.form_with(id: 'kc-form-login') do |f| 272 | username_field = f.field_with(id: 'username') 273 | username_field.value = 'service-manager@mailinator.com' 274 | password_field = f.field_with(id: 'password') 275 | password_field.value = 'service-manager' 276 | end.click_button 277 | 278 | # There is one more redirect after successful login 279 | download_page = after_login.forms.first.submit 280 | 281 | download_page.links.each do |link| 282 | next unless link.href =~ /#{Regexp.quote(CDK_BOX_BASE_NAME)}-#{Regexp.quote(provider)}.box/ 283 | agent.pluggable_parser.default = Mechanize::Download 284 | puts "Downloading public release CDK #{link.href}" 285 | agent.get(link.href).save(box_file) 286 | end 287 | end 288 | end 289 | 290 | def name 291 | 'cdk' 292 | end 293 | end 294 | -------------------------------------------------------------------------------- /locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | # Vagrant related translations 3 | vagrant: 4 | errors: 5 | url_validation_error: |- 6 | Download URL is not accessible. 7 | Possible reason: Invalid version name 8 | 9 | # Plugin related translations 10 | servicemanager: 11 | synopsis: |- 12 | provides the IP address:port and tls certificate file location for a docker daemon 13 | machine_should_running: |- 14 | The virtual machine must be running before you execute this command. 15 | Try this in the directory with your Vagrantfile: 16 | vagrant up 17 | 18 | # Config related translations 19 | config: 20 | supported_devices: |- 21 | services should be subset of %{services}. 22 | only_one_service: |- 23 | Only one of the service out of openshift and kubernetes can be enabled at a time. 24 | 25 | # Command related translations 26 | commands: 27 | help: 28 | default: |- 29 | Usage: vagrant service-manager [options] 30 | 31 | Commands: 32 | env displays connection information for services in the box 33 | box displays box related information like version, release, IP etc 34 | restart restarts the given service in the box 35 | start starts the given service in the box 36 | stop stops the given service in the box 37 | status list services and their running state 38 | install-cli install the client binary for the specified service 39 | 40 | Options: 41 | -h, --help print this help 42 | 43 | For help on any individual command run `vagrant service-manager COMMAND -h` 44 | env: |- 45 | Usage: vagrant service-manager env [object] [options] 46 | 47 | Objects: 48 | docker display information and environment variables for docker 49 | openshift display information and environment variables for openshift 50 | kubernetes display information and environment variables for kubernetes 51 | 52 | If OBJECT is omitted, display the information for all active services 53 | 54 | Options: 55 | --script-readable display information in a script readable format. 56 | -h, --help print this help 57 | box: |- 58 | Usage: vagrant service-manager box [options] 59 | 60 | Sub-Command: 61 | version display version and release information about the running VM 62 | ip display routable IP address of the running VM 63 | 64 | Options: 65 | --script-readable display information in a script readable format 66 | -h, --help print this help 67 | 68 | Examples: 69 | vagrant service-manager box version 70 | vagrant service-manager box version --script-readable 71 | vagrant service-manager box ip 72 | vagrant service-manager box ip --script-readable 73 | status: |- 74 | Usage: vagrant service-manager status [service] [options] 75 | 76 | Options: 77 | -h, --help print this help 78 | 79 | If a service is provided, only that service is reported. 80 | If no service is provided only supported orchestrators are reported. 81 | 82 | Example: 83 | vagrant service-manager status openshift 84 | operation: |- 85 | %{operation}s the service 86 | 87 | Usage: vagrant service-manager %{operation} [options] 88 | 89 | Service: 90 | A service provided by sccli. For example: 91 | docker, kubernetes, openshift etc 92 | 93 | Options: 94 | -h, --help print this help 95 | 96 | Examples: 97 | vagrant service-manager %{operation} docker 98 | install_cli: |- 99 | Install the client binary for the specified service 100 | 101 | Usage: vagrant service-manager install-cli [service] [options] 102 | 103 | Service: 104 | A supported service. For example: docker, kubernetes or openshift. 105 | 106 | Options: 107 | -h, --help print this help 108 | --cli-version binary version to install 109 | --path absolute or relative path where to install the binary 110 | 111 | Example: 112 | vagrant service-manager install-cli docker 113 | env: 114 | docker: 115 | windows: |- 116 | # Set the following environment variables to enable access to the 117 | # docker daemon running inside of the vagrant virtual machine: 118 | setx DOCKER_HOST tcp://%{ip}:%{port} 119 | setx DOCKER_CERT_PATH %{path} 120 | setx DOCKER_TLS_VERIFY 1 121 | setx DOCKER_API_VERSION %{api_version} 122 | non_windows: |- 123 | # Set the following environment variables to enable access to the 124 | # docker daemon running inside of the vagrant virtual machine: 125 | export DOCKER_HOST=tcp://%{ip}:%{port} 126 | export DOCKER_CERT_PATH=%{path} 127 | export DOCKER_TLS_VERIFY=1 128 | export DOCKER_API_VERSION=%{api_version} 129 | windows_cygwin: |- 130 | # Set the following environment variables to enable access to the 131 | # docker daemon running inside of the vagrant virtual machine: 132 | export DOCKER_HOST=tcp://%{ip}:%{port} 133 | export DOCKER_CERT_PATH='%{path}' 134 | export DOCKER_TLS_VERIFY=1 135 | export DOCKER_API_VERSION=%{api_version} 136 | script_readable: |- 137 | DOCKER_HOST=tcp://%{ip}:%{port} 138 | DOCKER_CERT_PATH='%{path}' 139 | DOCKER_TLS_VERIFY=1 140 | DOCKER_API_VERSION=%{api_version} 141 | openshift: 142 | windows: |- 143 | # You can access the OpenShift console on: %{openshift_console_url} 144 | # To use OpenShift CLI, run: oc login %{openshift_url} 145 | setx OPENSHIFT_URL %{openshift_url} 146 | setx OPENSHIFT_WEB_CONSOLE %{openshift_console_url} 147 | setx DOCKER_REGISTRY %{docker_registry} 148 | non_windows: |- 149 | # You can access the OpenShift console on: %{openshift_console_url} 150 | # To use OpenShift CLI, run: oc login %{openshift_url} 151 | export OPENSHIFT_URL=%{openshift_url} 152 | export OPENSHIFT_WEB_CONSOLE=%{openshift_console_url} 153 | export DOCKER_REGISTRY=%{docker_registry} 154 | windows_cygwin: |- 155 | # You can access the OpenShift console on: %{openshift_console_url} 156 | # To use OpenShift CLI, run: oc login %{openshift_url} 157 | export OPENSHIFT_URL=%{openshift_url} 158 | export OPENSHIFT_WEB_CONSOLE=%{openshift_console_url} 159 | export DOCKER_REGISTRY=%{docker_registry} 160 | script_readable: |- 161 | OPENSHIFT_URL=%{openshift_url} 162 | OPENSHIFT_WEB_CONSOLE=%{openshift_console_url} 163 | DOCKER_REGISTRY=%{docker_registry} 164 | kubernetes: 165 | windows: |- 166 | # Set the following environment variables to enable access to the 167 | # kubernetes server running inside of the vagrant virtual machine: 168 | setx KUBECONFIG %{kubeconfig_path} 169 | non_windows: |- 170 | # Set the following environment variables to enable access to the 171 | # kubernetes server running inside of the vagrant virtual machine: 172 | export KUBECONFIG=%{kubeconfig_path} 173 | windows_cygwin: |- 174 | # Set the following environment variables to enable access to the 175 | # kubernetes server running inside of the vagrant virtual machine: 176 | export KUBECONFIG=%{kubeconfig_path} 177 | script_readable: |- 178 | KUBECONFIG=%{kubeconfig_path} 179 | windows_cygwin_configure_info: |- 180 | # run following command to configure your shell: 181 | # eval "$(VAGRANT_NO_COLOR=1 vagrant service-manager env%{command} | tr -d '\r')" 182 | unix_configure_info: |- 183 | # run following command to configure your shell: 184 | # eval "$(vagrant service-manager env%{command})" 185 | service_not_running: |- 186 | # %{name} service is not running in the vagrant box. 187 | operation: 188 | service_missing: 'Service name missing' 189 | sccli_only_support: |- 190 | Only sccli services are supported. For example: 191 | docker, openshift and kubernetes 192 | start_service_first: 'Please start the service first before restarting.' 193 | install_cli: 194 | message: |- 195 | # Binary %{when} available at %{path} 196 | # run binary as: 197 | # %{binary} 198 | export PATH=%{dir}:$PATH 199 | 200 | # run following command to configure your shell: 201 | # eval "$(VAGRANT_NO_COLOR=1 vagrant service-manager install-cli %{service}%{options} | tr -d '\r')" 202 | service_not_enabled: |- 203 | '%{service}' service is not enabled. 204 | invalid_binary_path: |- 205 | Directory path %{dir_path} is invalid or doesn't exist. 206 | unsupported_version: |- 207 | Something went wrong to find the correct download link. 208 | We recommend you to use '--cli-version' for your desired client version. 209 | If you are still facing issues, please report to 210 | https://github.com/projectatomic/vagrant-service-manager. 211 | status: 212 | nil: |- 213 | Configured services: 214 | status: 215 | running: running 216 | stopped: stopped 217 | unsupported_service: |- 218 | Unknown service '%{service}'. 219 | Supported services are %{services}. 220 | 221 | # Action related translations 222 | actions: 223 | service_success: '%{service} service configured successfully...' 224 | service_failure: '%{service} service failed to configure properly...' 225 | private_network: |- 226 | When using Virtualbox, a non-NAT network interface is required. 227 | Adding a private network using DHCP 228 | 229 | # Kube config template translation 230 | kube_config: |- 231 | apiVersion: v1 232 | clusters: 233 | - cluster: 234 | insecure-skip-tls-verify: true 235 | server: https://%{ip}:6443 236 | name: k8s 237 | contexts: 238 | - context: 239 | cluster: k8s 240 | user: "serviceaccount" 241 | name: k8s 242 | current-context: k8s 243 | kind: Config 244 | preferences: {} 245 | users: 246 | - name: serviceaccount 247 | user: 248 | token: %{token} 249 | -------------------------------------------------------------------------------- /commands.adoc: -------------------------------------------------------------------------------- 1 | = Available Commands and Examples 2 | :toc: 3 | :toc-placement!: 4 | 5 | Once you start the virtual machine using `vagrant up`, you can use 6 | vagrant-service-manager to manage your development environment. 7 | 8 | ''' 9 | toc::[] 10 | ''' 11 | 12 | You can use vagrant-service-manager to set up your environment variables and 13 | get the TLS certificates to secure the Docker communication channel; identify 14 | the routable ip address and version of your VM; and check the status and 15 | manage the life cycle of the configured services in the development environment. 16 | 17 | To run the vagrant-service-manager plugin use: + 18 | ------------------------------------------- 19 | vagrant service-manager [command] [options] 20 | ------------------------------------------- 21 | The following commands can be used: + 22 | 23 | `env`:: Displays the connection information for services in the VM + 24 | `box`:: Displays the VM related information like version, release, IP etc + 25 | `status`:: Lists services and their running state + 26 | `start`:: Starts the given service in the VM + 27 | `stop`:: Stops the given service in the VM + 28 | `restart`:: Restarts the given service in the VM + 29 | 30 | The following options can be used: + 31 | 32 | `--script-readable`:: Displays information in a key=value format + 33 | `-h, --help`:: Prints help for the specific command being run + 34 | 35 | 36 | == Set Environment Variables and Get Certificates 37 | 38 | If you need to set the environment variables and get the certificates for all 39 | active services in the VM, run: + 40 | 41 | `$ vagrant service-manager env` + 42 | 43 | Usage: `vagrant service-manager env [service] [options]` 44 | 45 | The possible options for service are `docker` and `openshift`. + 46 | If no service is specified `vagrant service-manager env` provides connection 47 | information for all active services. 48 | 49 | The following options can be used: + 50 | 51 | `--script-readable`:: Displays information in a key=value format + 52 | `-h, --help`:: Prints help for the specific command being run. + 53 | 54 | === Examples 55 | 56 | If you need connection information for all active services in the VM, in a 57 | manner that can be evaluated in a shell, use: 58 | ----------------------------------------------------------------------------- 59 | $ vagrant service-manager env 60 | 61 | # docker env: 62 | # Set the following environment variables to enable access to the 63 | # docker daemon running inside of the vagrant virtual machine: 64 | export DOCKER_HOST=tcp://10.1.2.2:2376 65 | export DOCKER_CERT_PATH=/foo/bar/.vagrant/machines/default/virtualbox/docker 66 | export DOCKER_TLS_VERIFY=1 67 | export DOCKER_API_VERSION=1.21 68 | 69 | # openshift env: 70 | # You can access the OpenShift console on: https://10.1.2.2:8443/console 71 | # To use OpenShift CLI, run: oc login https://10.1.2.2:8443 72 | export OPENSHIFT_URL=https://10.1.2.2:8443 73 | export OPENSHIFT_WEB_CONSOLE=https://10.1.2.2:8443/console 74 | export DOCKER_REGISTRY=hub.openshift.centos7-adb.10.1.2.2.xip.io 75 | 76 | # run following command to configure your shell: 77 | # eval "$(vagrant service-manager env)" 78 | ----------------------------------------------------------------------------- 79 | 80 | If you would like to get the environment variables, and if applicable, 81 | certificates for a specific service, specify the service name. For example, for 82 | Docker use: + 83 | 84 | ---------------------------------------------------------------------------- 85 | $ vagrant service-manager env docker 86 | # Set the following environment variables to enable access to the 87 | # docker daemon running inside of the vagrant virtual machine: 88 | export DOCKER_HOST=tcp://172.28.128.3:2376 89 | export DOCKER_CERT_PATH=/foo/bar/.vagrant/machines/default/virtualbox/docker 90 | export DOCKER_TLS_VERIFY=1 91 | export DOCKER_API_VERSION=1.21 92 | 93 | # run following command to configure your shell: 94 | # eval "$(vagrant service-manager env docker)" 95 | ---------------------------------------------------------------------------- 96 | 97 | NOTE: The `env` command checks to make sure that the TLS certificate on the host 98 | used with docker is valid. If it is invalid, the command will automatically 99 | regenerate the docker TLS certificate and copy the new certificate to the host. 100 | 101 | Similarly, for OpenShift you can use: + 102 | `$ vagrant service-manager env openshift` 103 | 104 | If you want to run the plugin and get the environment variables and certificates 105 | for docker in key=value format, use: 106 | ---------------------------------------------------------------------- 107 | $ vagrant service-manager env docker --script-readable 108 | DOCKER_HOST=tcp://172.28.128.3:2376 109 | DOCKER_CERT_PATH=/foo/bar/.vagrant/machines/default/virtualbox/docker' 110 | DOCKER_TLS_VERIFY=1 111 | DOCKER_API_VERSION=1.21 112 | ---------------------------------------------------------------------- 113 | 114 | 115 | == Get IP Address and Version Information 116 | 117 | If you need information about the development environment, such as the routable 118 | IP address or the version and release information, use: 119 | 120 | `$ vagrant service-manager box` + 121 | 122 | Usage: `vagrant service-manager box [sub-command] [options]` 123 | 124 | The following sub-commands can be used: + 125 | 126 | `ip`:: Displays the routable IP address of the VM + 127 | `version`:: Displays the version and release information of the VM + 128 | 129 | The following options can be used: + 130 | 131 | `--script-readable`:: Displays information in a key=value format + 132 | `-h, --help`:: Prints help for the specific command being run. 133 | 134 | === Examples 135 | 136 | To check the routable IP address of the VM: 137 | --------------------------------- 138 | $ vagrant service-manager box ip 139 | 172.28.128.3 140 | --------------------------------- 141 | 142 | To check the routable IP address of the VM in key=value format: 143 | --------------------------------------------------- 144 | $ vagrant service-manager box ip --script-readable 145 | IP=172.28.128.3 146 | --------------------------------------------------- 147 | 148 | To check the version information: 149 | -------------------------------------- 150 | $ vagrant service-manager box version 151 | Atomic Developer Bundle (ADB) 2.2.0 152 | -------------------------------------- 153 | 154 | To get the version information in key=value format: 155 | -------------------------------------------------------- 156 | $ vagrant service-manager box version --script-readable 157 | VARIANT="Atomic Developer Bundle (ADB)" 158 | VARIANT_ID="adb" 159 | VARIANT_VERSION="2.2.0" 160 | -------------------------------------------------------- 161 | 162 | 163 | == Manage Services 164 | 165 | If you need to check the status, start, stop or restart a specific service use: + 166 | `$ vagrant service-manager [sub-command] [service]` 167 | 168 | The following sub-commands can be used: + 169 | 170 | `status`:: Lists services and their state (running/stopped) + 171 | `start`:: Starts the given service in the VM + 172 | `stop`:: Stops the given service in the VM + 173 | `restart`:: Restarts the given service in the VM + 174 | 175 | The possible options for service are `docker`, `openshift` and `kubernetes`. 176 | 177 | === Examples 178 | 179 | If no service is specified `vagrant service-manager status` will provide 180 | information on all the configured services and their state (running/stopped). 181 | --------------------------------------- 182 | $ vagrant service-manager status 183 | Configured services: 184 | docker - running 185 | openshift - stopped 186 | kubernetes - stopped 187 | --------------------------------------- 188 | 189 | To check the status of Docker: 190 | ------------------------------------------- 191 | $ vagrant service-manager status docker 192 | docker - running 193 | ------------------------------------------- 194 | 195 | To start Docker, if it is stopped: 196 | --------------------------------------------- 197 | $ vagrant service-manager start docker 198 | $ vagrant service-manager status docker 199 | docker - running 200 | --------------------------------------------- 201 | 202 | To stop Docker: 203 | --------------------------------------------- 204 | $ vagrant service-manager stop docker 205 | $ vagrant service-manager status docker 206 | docker - stopped 207 | --------------------------------------------- 208 | 209 | To restart Docker: 210 | ----------------------------------------- 211 | $ vagrant service-manager restart docker 212 | $ vagrant service-manager status docker 213 | docker - running 214 | ----------------------------------------- 215 | 216 | Similarly, you can use `$ vagrant service-manager status openshift`, 217 | `$ vagrant service-manager start openshift`, `$ vagrant service-manager stop openshift`, 218 | and `$ vagrant service-manager restart openshift`, to verify the status, start, 219 | stop and restart OpenShift. 220 | 221 | 222 | == Install CLI 223 | 224 | If you need to install the client binary for a specified service, use: + 225 | 226 | `vagrant service-manager install-cli [service] [options]` + 227 | 228 | The possible options for service are `docker` and `openshift`. + 229 | 230 | The following options can be used: + 231 | 232 | `--cli-version value`:: Specify the version of the binary as value to be installed + 233 | `--path value`:: Specify the absolute or relative path as value where the binary should be installed + 234 | `-h, --help`:: Prints help for the specific command being run. 235 | 236 | As per default, binaries are downloaded to 237 | `$VAGRANT_HOME/data/service-manager/bin//`, where 238 | `$VAGRANT_HOME` defaults to `.vagrant.d` in your home directory. 239 | 240 | === Example 241 | 242 | To install client binary for Docker: 243 | 244 | ---------------------------------------------------------------------------------------------------- 245 | $ vagrant service-manager install-cli docker --cli-version 1.9.1 --path /home/johndoe/bin 246 | # Binary already available at /home/johndoe/bin/docker 247 | # run binary as: 248 | # docker 249 | export PATH=/home/johndoe/bin:$PATH 250 | 251 | # run following command to configure your shell: 252 | # eval "$(VAGRANT_NO_COLOR=1 vagrant service-manager install-cli docker --path /home/johndoe/bin | tr -d '\r')" 253 | ---------------------------------------------------------------------------------------------------- 254 | 255 | 256 | == Access Help 257 | If you need information on the possible commands, options and other relevant 258 | information for the vagrant-service-manager plugin, access the help by using 259 | `--help` or `-h` as is shown below: 260 | 261 | -------------------------------------------------------------------------------- 262 | $ vagrant service-manager [--help | -h] 263 | Usage: vagrant service-manager [options] 264 | 265 | The following commands can be used: 266 | env: displays connection information for services in the VM 267 | box: displays VM related information like version, release, IP etc 268 | status: lists services and their running state 269 | start: starts the given service in the VM 270 | stop: stops the given service in the VM 271 | restart: restarts the given service in the VM 272 | 273 | The following options can be used: 274 | --script-readable : Displays information in a key=value format 275 | -h, --help print this help 276 | 277 | For help on any individual command run `vagrant service-manager -h` 278 | -------------------------------------------------------------------------------- 279 | -------------------------------------------------------------------------------- /lib/vagrant-service-manager/command.rb: -------------------------------------------------------------------------------- 1 | require 'digest' 2 | require_relative 'plugin_util' 3 | require_relative 'plugin_logger' 4 | require_relative 'installer' 5 | require_relative 'archive_handlers/tar_handler' 6 | require_relative 'archive_handlers/zip_handler' 7 | require_relative 'binary_handlers/binary_handler' 8 | require_relative 'binary_handlers/adb_binary_handler' 9 | require_relative 'binary_handlers/cdk_binary_handler' 10 | require_relative 'binary_handlers/adb_docker_binary_handler' 11 | require_relative 'binary_handlers/cdk_docker_binary_handler' 12 | require_relative 'binary_handlers/adb_openshift_binary_handler' 13 | require_relative 'binary_handlers/cdk_openshift_binary_handler' 14 | require_relative 'binary_handlers/adb_kubernetes_binary_handler' 15 | require_relative 'binary_handlers/cdk_kubernetes_binary_handler' 16 | 17 | module VagrantPlugins 18 | module ServiceManager 19 | DOCKER_PATH = '/home/vagrant/.docker'.freeze 20 | SUPPORTED_SERVICES = %w(docker openshift kubernetes).freeze 21 | KUBE_SERVICES = [ 22 | 'etcd', 'kube-apiserver', 'kube-controller-manager', 'kube-scheduler', 23 | 'kubelet', 'kube-proxy', 'docker' 24 | ].freeze 25 | # NOTE: SERVICES_MAP[] will give fully-qualified service class name 26 | # Eg: SERVICES_MAP['docker'] gives Vagrant::ServiceManager::Docker 27 | SERVICES_MAP = { 28 | 'docker' => Docker, 'openshift' => OpenShift, 29 | 'kubernetes' => Kubernetes 30 | }.freeze 31 | 32 | def self.bin_dir 33 | @bin_dir 34 | end 35 | 36 | def self.temp_dir 37 | @temp_dir 38 | end 39 | 40 | def self.bin_dir=(path) 41 | @bin_dir = path 42 | end 43 | 44 | def self.temp_dir=(path) 45 | @temp_dir = path 46 | end 47 | 48 | class Command < Vagrant.plugin(2, :command) 49 | OS_RELEASE_FILE = '/etc/os-release'.freeze 50 | 51 | def self.synopsis 52 | I18n.t('servicemanager.synopsis') 53 | end 54 | 55 | def exit_if_machine_not_running 56 | # Exit from plugin with status 3 if machine is not running 57 | with_target_vms(nil, single_target: true) do |machine| 58 | PluginLogger.debug("machine state - #{machine.state.id || 'nil'}") 59 | if machine.state.id != :running 60 | @env.ui.error I18n.t('servicemanager.machine_should_running') 61 | exit 3 62 | end 63 | end 64 | end 65 | 66 | def execute 67 | ServiceManager.bin_dir = "#{@env.data_dir}/service-manager/bin" 68 | ServiceManager.temp_dir = "#{@env.data_dir}/service-manager/tmp" 69 | 70 | argv = ARGV.dup 71 | # Don't propagate --debug argument to case operation 72 | if ARGV.include? '--debug' 73 | PluginLogger.enable_debug_mode 74 | PluginLogger.logger = @logger 75 | argv.delete('--debug') 76 | end 77 | 78 | # Remove first argument i.e plugin name 79 | command, subcommand, option = argv.drop(1) 80 | case command 81 | when 'env' 82 | exit_if_machine_not_running 83 | case subcommand 84 | when 'docker', 'openshift', 'kubernetes' 85 | case option 86 | when nil 87 | execute_service(subcommand) 88 | when '--script-readable' 89 | execute_service(subcommand, script_readable: true) 90 | when '--help', '-h' 91 | print_help(type: command) 92 | else 93 | print_help(type: command, exit_status: 1) 94 | end 95 | when nil 96 | # display information about all the providers inside ADB/CDK 97 | print_all_provider_info 98 | when '--script-readable' 99 | print_all_provider_info(script_readable: true) 100 | when '--help', '-h' 101 | print_help(type: command) 102 | else 103 | print_help(type: command, exit_status: 1) 104 | end 105 | when 'status' 106 | exit_if_machine_not_running 107 | case subcommand 108 | when nil 109 | execute_status_display 110 | when '--help', '-h' 111 | print_help(type: command) 112 | else 113 | execute_status_display(subcommand) 114 | end 115 | when 'box' 116 | exit_if_machine_not_running 117 | case subcommand 118 | when 'version' 119 | case option 120 | when nil 121 | print_vagrant_box_version 122 | when '--script-readable' 123 | print_vagrant_box_version(true) 124 | when '--help', '-h' 125 | print_help(type: command) 126 | else 127 | print_help(type: command, exit_status: 1) 128 | end 129 | when 'ip' 130 | case option 131 | when nil 132 | display_box_ip 133 | when '--script-readable' 134 | display_box_ip(true) 135 | when '--help', '-h' 136 | print_help(type: command) 137 | else 138 | print_help(type: command, exit_status: 1) 139 | end 140 | when '--help', '-h' 141 | print_help(type: command) 142 | else 143 | print_help(type: command, exit_status: 1) 144 | end 145 | when 'restart', 'start', 'stop' 146 | exit_if_machine_not_running 147 | case subcommand 148 | when '--help', '-h' 149 | print_help(type: 'operation', operation: command) 150 | else 151 | perform_service(command, subcommand) 152 | end 153 | when 'install-cli' 154 | exit_if_machine_not_running 155 | # Transform hyphen into underscore which is valid char in method 156 | command = command.tr('-', '_') 157 | # Get options as Hash which are preceeded with -- like --version 158 | options = Hash[ARGV.drop(3).each_slice(2).to_a] 159 | 160 | case subcommand 161 | when '--help', '-h' 162 | print_help(type: command) 163 | else 164 | execute_install_cli(subcommand, options) 165 | end 166 | when '--help', '-h', 'help' 167 | print_help 168 | else 169 | print_help(exit_status: 1) 170 | end 171 | end 172 | 173 | def execute_service(name, options = {}) 174 | with_target_vms(nil, single_target: true) do |machine| 175 | PluginUtil.service_class(name).new(machine, @env).info(options) 176 | end 177 | end 178 | 179 | def print_help(config = {}) 180 | config[:type] ||= 'default' 181 | config[:exit_status] ||= 0 182 | 183 | @env.ui.info(I18n.t("servicemanager.commands.help.#{config[:type]}", operation: config[:operation])) 184 | exit config[:exit_status] 185 | end 186 | 187 | def execute_status_display(service = nil) 188 | with_target_vms(nil, single_target: true) do |machine| 189 | if service && SUPPORTED_SERVICES.include?(service) 190 | PluginUtil.service_class(service).new(machine, @env).status 191 | elsif service.nil? 192 | @env.ui.info I18n.t('servicemanager.commands.status.nil') 193 | SUPPORTED_SERVICES.each do |s| 194 | PluginUtil.service_class(s).new(machine, @env).status 195 | end 196 | else 197 | @env.ui.error I18n.t('servicemanager.commands.status.unsupported_service', 198 | service: service, services: SUPPORTED_SERVICES.join(', ') + ' etc') 199 | exit 126 200 | end 201 | end 202 | end 203 | 204 | def print_all_provider_info(options = {}) 205 | with_target_vms(nil, single_target: true) do |machine| 206 | options[:all] = true # flag to mark all providers 207 | running_service_classes = PluginUtil.running_services(machine, class: true) 208 | 209 | running_service_classes.each do |service_class| 210 | service = service_class.to_s.split('::').last.downcase 211 | @env.ui.info("\n# #{service} env:") unless options[:script_readable] 212 | service_class.new(machine, @env).info(options) 213 | end 214 | 215 | PluginUtil.print_shell_configure_info(@env.ui) unless options[:script_readable] 216 | end 217 | end 218 | 219 | def print_vagrant_box_version(script_readable = false) 220 | options = { script_readable: script_readable } 221 | 222 | with_target_vms(nil, single_target: true) do |machine| 223 | @env.ui.info machine.guest.capability(:box_version, options) 224 | end 225 | end 226 | 227 | def perform_service(operation, service) 228 | if service.nil? 229 | help_msg = I18n.t('servicemanager.commands.help.operation', operation: operation) 230 | service_missing_msg = I18n.t('servicemanager.commands.operation.service_missing') 231 | @env.ui.error help_msg.gsub(/#{operation}s the service/, service_missing_msg) 232 | exit 126 233 | end 234 | 235 | command = if SUPPORTED_SERVICES.include? service 236 | # TODO : Handle the case where user wants to pass extra arguments 237 | # to OpenShift service 238 | "sccli #{service} #{operation}" 239 | else 240 | @env.ui.error I18n.t('servicemanager.commands.operation.sccli_only_support') 241 | exit 126 242 | end 243 | 244 | with_target_vms(nil, single_target: true) do |machine| 245 | exit_code = PluginUtil.execute_and_exit_on_fail(machine, @env.ui, command) 246 | 247 | if exit_code.zero? && service == 'kubernetes' && operation == 'start' 248 | PluginUtil.generate_kubeconfig(machine, @env.ui, File.dirname(ServiceManager.bin_dir)) 249 | end 250 | end 251 | rescue StandardError => e 252 | if operation == 'restart' && e.message.include?("Start #{service} first") 253 | @env.ui.error I18n.t('servicemanager.commands.operation.start_service_first') 254 | else 255 | @env.ui.error e.message.squeeze 256 | end 257 | 258 | exit 126 259 | end 260 | 261 | def display_box_ip(script_readable = false) 262 | options = { script_readable: script_readable } 263 | 264 | with_target_vms(nil, single_target: true) do |machine| 265 | @env.ui.info machine.guest.capability(:machine_ip, options) 266 | end 267 | end 268 | 269 | def execute_install_cli(service, options = {}) 270 | help_msg = I18n.t('servicemanager.commands.help.install_cli') 271 | 272 | if service.nil? 273 | service_missing_msg = I18n.t('servicemanager.commands.operation.service_missing') 274 | @env.ui.error help_msg.gsub(/Install the client side tool for the service/, service_missing_msg) 275 | exit 126 276 | end 277 | 278 | unless SUPPORTED_SERVICES.include?(service) 279 | @env.ui.error "Unknown service '#{service}'." 280 | @env.ui.error help_msg.gsub(/Install the client side tool for the service\n/, '') 281 | exit 126 282 | end 283 | 284 | with_target_vms(nil, single_target: true) do |machine| 285 | options[:type] = service.to_sym 286 | args = [machine, @env, options] 287 | 288 | begin 289 | args.last[:box_version] = machine.guest.capability(:os_variant) 290 | Installer.new(*args).install 291 | rescue Vagrant::Errors::GuestCapabilityNotFound 292 | @env.ui.info 'Not a supported box.' 293 | exit 126 294 | rescue StandardError => e 295 | @env.ui.error e.message 296 | exit 126 297 | end 298 | end 299 | end 300 | end 301 | end 302 | end 303 | -------------------------------------------------------------------------------- /features/docker.feature: -------------------------------------------------------------------------------- 1 | Feature: Command output from box command 2 | service-manager should return the correct output from box commands 3 | 4 | Scenario Outline: Boot and execute box commands 5 | Given box is 6 | And provider is 7 | And a file named "Vagrantfile" with: 8 | """ 9 | begin 10 | require 'vagrant-libvirt' 11 | rescue LoadError 12 | # NOOP 13 | end 14 | 15 | Vagrant.configure('2') do |config| 16 | config.vm.box = '' 17 | config.vm.box_url = 'file://../../.boxes/-.box' 18 | config.vm.network :private_network, ip: '' 19 | config.vm.synced_folder '.', '/vagrant', disabled: true 20 | config.servicemanager.services = 'docker' 21 | end 22 | """ 23 | 24 | When I run `bundle exec vagrant up --provider ` 25 | Then the exit status should be 0 26 | And stdout from "bundle exec vagrant up --provider " should contain: 27 | """ 28 | ==> default: Docker service configured successfully... 29 | """ 30 | 31 | #################################################################################################################### 32 | # BOX command 33 | #################################################################################################################### 34 | When I run `bundle exec vagrant service-manager box` 35 | Then the exit status should be 1 36 | And stdout from "bundle exec vagrant service-manager box" should contain: 37 | """ 38 | Usage: vagrant service-manager box [options] 39 | 40 | Sub-Command: 41 | version display version and release information about the running VM 42 | ip display routable IP address of the running VM 43 | 44 | Options: 45 | --script-readable display information in a script readable format 46 | -h, --help print this help 47 | """ 48 | 49 | When I successfully run `bundle exec vagrant service-manager box --help` 50 | Then the exit status should be 0 51 | And stdout from "bundle exec vagrant service-manager box --help" should contain: 52 | """ 53 | Usage: vagrant service-manager box [options] 54 | 55 | Sub-Command: 56 | version display version and release information about the running VM 57 | ip display routable IP address of the running VM 58 | 59 | Options: 60 | --script-readable display information in a script readable format 61 | -h, --help print this help 62 | 63 | Examples: 64 | vagrant service-manager box version 65 | vagrant service-manager box version --script-readable 66 | vagrant service-manager box ip 67 | vagrant service-manager box ip --script-readable 68 | """ 69 | 70 | When I successfully run `bundle exec vagrant service-manager box ip` 71 | Then stdout from "bundle exec vagrant service-manager box ip" should contain "" 72 | 73 | When I successfully run `bundle exec vagrant service-manager box ip --script-readable` 74 | Then stdout from "bundle exec vagrant service-manager box ip --script-readable" should contain "IP=" 75 | And stdout from "bundle exec vagrant service-manager box ip --script-readable" should be script readable 76 | 77 | When I successfully run `bundle exec vagrant service-manager box version` 78 | Then stdout from "bundle exec vagrant service-manager box version" should match /(Container Development Kit \(CDK\) \d.\d.?\d?|Atomic Developer Bundle \(ADB\) \d.\d.?\d?)/ 79 | 80 | When I successfully run `bundle exec vagrant service-manager box version --script-readable` 81 | Then stdout from "bundle exec vagrant service-manager box version --script-readable" should match /(Container Development Kit \(CDK\)|Atomic Developer Bundle \(ADB\))/ 82 | And stdout from "bundle exec vagrant service-manager box version --script-readable" should match /VARIANT_ID=""/ 83 | And stdout from "bundle exec vagrant service-manager box version --script-readable" should match /VARIANT_VERSION="\d.\d.?\d?"/ 84 | And stdout from "bundle exec vagrant service-manager box version --script-readable" should be script readable 85 | 86 | #################################################################################################################### 87 | # ENV command 88 | #################################################################################################################### 89 | When I successfully run `bundle exec vagrant service-manager env --help` 90 | Then the exit status should be 0 91 | And stdout from "bundle exec vagrant service-manager env --help" should contain: 92 | """ 93 | Usage: vagrant service-manager env [object] [options] 94 | 95 | Objects: 96 | docker display information and environment variables for docker 97 | openshift display information and environment variables for openshift 98 | kubernetes display information and environment variables for kubernetes 99 | 100 | If OBJECT is omitted, display the information for all active services 101 | 102 | Options: 103 | --script-readable display information in a script readable format. 104 | -h, --help print this help 105 | """ 106 | 107 | When I successfully run `bundle exec vagrant service-manager env` 108 | Then stdout from "bundle exec vagrant service-manager env" should be evaluable in a shell 109 | 110 | When I successfully run `bundle exec vagrant service-manager env --script-readable` 111 | Then stdout from "bundle exec vagrant service-manager env --script-readable" should be script readable 112 | 113 | When I successfully run `bundle exec vagrant service-manager env docker` 114 | Then stdout from "bundle exec vagrant service-manager env docker" should be evaluable in a shell 115 | And stdout from "bundle exec vagrant service-manager env docker" should contain "export DOCKER_HOST=tcp://:2376" 116 | And stdout from "bundle exec vagrant service-manager env docker" should match /export DOCKER_CERT_PATH=.*\/.vagrant\/machines\/cdk\/virtualbox\/docker/ 117 | And stdout from "bundle exec vagrant service-manager env docker" should contain "export DOCKER_TLS_VERIFY=1" 118 | And stdout from "bundle exec vagrant service-manager env docker" should match /export DOCKER_API_VERSION=1.2\d/ 119 | And stdout from "bundle exec vagrant service-manager env docker" should match /# eval "\$\(vagrant service-manager env docker\)"/ 120 | 121 | When I successfully run `bundle exec vagrant service-manager env docker --script-readable` 122 | Then stdout from "bundle exec vagrant service-manager env docker --script-readable" should be script readable 123 | 124 | When I run `bundle exec vagrant service-manager env openshift` 125 | Then the exit status should be 126 126 | And stderr from "bundle exec vagrant service-manager env openshift" should contain: 127 | """ 128 | # OpenShift service is not running in the vagrant box. 129 | """ 130 | 131 | When I successfully run `bundle exec vagrant service-manager env --debug` 132 | Then stdout from "bundle exec vagrant service-manager env --debug" should match /DEBUG command: [ service-manager: env ]/ 133 | 134 | 135 | #################################################################################################################### 136 | # INSTALL-CLI command 137 | #################################################################################################################### 138 | When I successfully run `bundle exec vagrant service-manager install-cli --help` 139 | Then the exit status should be 0 140 | And stdout from "bundle exec vagrant service-manager install-cli --help" should contain: 141 | """ 142 | Install the client binary for the specified service 143 | 144 | Usage: vagrant service-manager install-cli [service] [options] 145 | 146 | Service: 147 | A supported service. For example: docker, kubernetes or openshift. 148 | 149 | Options: 150 | -h, --help print this help 151 | --cli-version binary version to install 152 | --path absolute or relative path where to install the binary 153 | 154 | Example: 155 | vagrant service-manager install-cli docker 156 | """ 157 | 158 | When I run `bundle exec vagrant service-manager install-cli` 159 | Then the exit status should be 126 160 | And stdout from "bundle exec vagrant service-manager install-cli" should match /Service name missing/ 161 | 162 | When I run `bundle exec vagrant service-manager install-cli docker --cli-version 111.222.333` 163 | Then the exit status should be 126 164 | 165 | When I run `bundle exec vagrant service-manager install-cli docker` 166 | Then the exit status should be 0 167 | And the binary "docker" should be installed 168 | And the stderr should not contain anything 169 | 170 | When I run `bundle exec vagrant service-manager install-cli docker --cli-version 1.12.1` 171 | Then the exit status should be 0 172 | And the binary "docker" of service "docker" should be installed with version "1.12.1" 173 | And the stderr should not contain anything 174 | 175 | When I evaluate and run `bundle exec vagrant service-manager install-cli docker --path #{ENV['VAGRANT_HOME']}` 176 | Then the exit status should be 0 177 | And the binary should be installed in path "#{ENV['VAGRANT_HOME']}/docker" 178 | And the stderr should not contain anything 179 | 180 | When I evaluate and run `bundle exec vagrant service-manager install-cli docker --path #{ENV['VAGRANT_HOME']}/unknown_dir` 181 | Then the exit status should be 126 182 | And stderr from evaluating and running "bundle exec vagrant service-manager install-cli docker --path #{ENV['VAGRANT_HOME']}/unknown_dir" should match /Directory path #{ENV['VAGRANT_HOME']}/unknown_dir is invalid or doesn't exist/ 183 | 184 | When I run `bundle exec vagrant service-manager install-cli docker --path /foo/bar` 185 | Then the exit status should be 126 186 | And stderr from evaluating and running "bundle exec vagrant service-manager install-cli docker --path /foo/bar" should match /Permission denied @ dir_s_mkdir - /foo/ 187 | 188 | #################################################################################################################### 189 | # START/STOP/STATUS/RESTART command 190 | #################################################################################################################### 191 | When I successfully run `bundle exec vagrant service-manager status --help` 192 | Then the exit status should be 0 193 | And stdout from "bundle exec vagrant service-manager status --help" should contain: 194 | """ 195 | Usage: vagrant service-manager status [service] [options] 196 | 197 | Options: 198 | -h, --help print this help 199 | 200 | If a service is provided, only that service is reported. 201 | If no service is provided only supported orchestrators are reported. 202 | 203 | Example: 204 | vagrant service-manager status openshift 205 | """ 206 | 207 | And I successfully run `bundle exec vagrant service-manager stop --help` 208 | Then the exit status should be 0 209 | And stdout from "bundle exec vagrant service-manager stop --help" should contain: 210 | """ 211 | stops the service 212 | 213 | Usage: vagrant service-manager stop [options] 214 | 215 | Service: 216 | A service provided by sccli. For example: 217 | docker, kubernetes, openshift etc 218 | 219 | Options: 220 | -h, --help print this help 221 | 222 | Examples: 223 | vagrant service-manager stop docker 224 | """ 225 | 226 | And I successfully run `bundle exec vagrant service-manager start --help` 227 | Then the exit status should be 0 228 | And stdout from "bundle exec vagrant service-manager start --help" should contain: 229 | """ 230 | starts the service 231 | 232 | Usage: vagrant service-manager start [options] 233 | 234 | Service: 235 | A service provided by sccli. For example: 236 | docker, kubernetes, openshift etc 237 | 238 | Options: 239 | -h, --help print this help 240 | 241 | Examples: 242 | vagrant service-manager start docker 243 | """ 244 | 245 | And I successfully run `bundle exec vagrant service-manager restart --help` 246 | Then the exit status should be 0 247 | And stdout from "bundle exec vagrant service-manager restart --help" should contain: 248 | """ 249 | restarts the service 250 | 251 | Usage: vagrant service-manager restart [options] 252 | 253 | Service: 254 | A service provided by sccli. For example: 255 | docker, kubernetes, openshift etc 256 | 257 | Options: 258 | -h, --help print this help 259 | 260 | Examples: 261 | vagrant service-manager restart docker 262 | """ 263 | 264 | When I successfully run `bundle exec vagrant service-manager status` 265 | Then stdout from "bundle exec vagrant service-manager status" should contain "docker - running" 266 | Then stdout from "bundle exec vagrant service-manager status" should contain "openshift - stopped" 267 | Then stdout from "bundle exec vagrant service-manager status" should contain "kubernetes - stopped" 268 | 269 | When I successfully run `bundle exec vagrant service-manager status docker` 270 | Then stdout from "bundle exec vagrant service-manager status" should contain "docker - running" 271 | 272 | When I run `bundle exec vagrant service-manager status abcd` 273 | Then the exit status should be 126 274 | And stderr from "bundle exec vagrant service-manager status abcd" should contain: 275 | """ 276 | Unknown service 'abcd'. 277 | Supported services are docker, openshift, kubernetes etc. 278 | """ 279 | 280 | When the "docker" service is running 281 | And I successfully run `bundle exec vagrant service-manager stop docker` 282 | Then the service "docker" should be stopped 283 | 284 | When the "docker" service is not running 285 | And I successfully run `bundle exec vagrant service-manager start docker` 286 | Then the service "docker" should be running 287 | 288 | When the "docker" service is running 289 | And I successfully run `bundle exec vagrant service-manager restart docker` 290 | Then the service "docker" should be running 291 | And have a new pid for "docker" service 292 | 293 | Examples: 294 | | box | provider | ip | 295 | | cdk | virtualbox | 10.10.10.42 | 296 | | adb | virtualbox | 10.10.10.42 | 297 | | cdk | libvirt | 10.10.10.42 | 298 | | adb | libvirt | 10.10.10.42 | 299 | -------------------------------------------------------------------------------- /CHANGELOG.adoc: -------------------------------------------------------------------------------- 1 | = Revision History 2 | :toc: 3 | 4 | [[v1.5.0-jan-24-2017]] 5 | == 1.5.0 January 24, 2017 6 | * Fix #446 Support folder as path in install-cli '--path' option @budhrg 7 | * Fix #441 install-cli with --path give wrong export @budhrg 8 | * Fix #449 Update ‘oc’ version getting installed via install-cli to 1.4.0 @budhrg 9 | * Fix #443 Double quote is missing in the HTTP Proxy Settings doc @budhrg 10 | * Fix adb-atomic-developer-bundle doc url on README @trishnaguha 11 | 12 | [[v1.4.1-nov-17-2016]] 13 | == 1.4.1 November 17, 2016 14 | * Fix #346 Adding a Rake task for Asciidoctor and enabling Guard and Live Reload @hferentschik 15 | * Fix #389 Refactoring proxy test @hferentschik 16 | * Fix #389 Support the use of install-cli in HTTP proxy environment @budhrg 17 | * Fix #434 Align proxy config names similar to 'sccli' @budhrg 18 | * Fix #362 Adding OpenShift configuration options back into VSM Readme @Preeticp 19 | * Fix #335 'bundle exec vagrant up --provider=libvirt' should work @budhrg 20 | * Fix #429 Minor language and formatting edits to Proxy section etc @Preeticp 21 | * Fix #427 Add acceptance test for 'box version' command @budhrg 22 | * Fix #425 Disabling CDK OpenShift tests until issue #415 gets resolved @hferentschik 23 | * Fix #425 Organizing Cucumber features around service functionality @hferentschik 24 | * Fix #419 Adding additional column to example table to print status [passed|failure|skipped] @hferentschik 25 | * Fix #417 Updated rake task to download latest CDK version @budhrg 26 | * Fix #421 Correct the order of drafting the release and updating to dev version @budhrg 27 | 28 | [[v1.4.0-oct-21-2016]] 29 | == 1.4.0 October 21, 2016 30 | * Fix #376 --path option of install cli not working as expected @budhrg 31 | * Fix #327 and #326: Tests and docs for --cli-version and --path options @budhrg 32 | * Fix #412 Pin the rubocop version and minimize the offenses @budhrg 33 | * Fix #409 fixes Openshift service failed message on vagrant up @budhrg 34 | * Fix #406 Service hooks doesn't start in vagrant reload @budhrg 35 | * Fix #338 Updating broken links in CONTRIBUTING.adoc @Preeticp 36 | * Fix #407 Converted CHANGELOG from markdown to asciidoc @thatdocslady 37 | * Fix #402 rename open_shift.rb file to openshift @budhrg 38 | * Fix #302 service-manager config options for HTTP proxy @budhrg 39 | * Fix #393 Fix expectations for Kubernetes tests on OS X @budhrg 40 | * Fix #394 Forcing used Bundler version to 1.12.5 as required by Vagrant @hferentschik 41 | * Fix #397 Using a guard clause instead of wrapping the code inside a conditional @hferentschik 42 | 43 | [[v1.3.3-sep-1-2016]] 44 | == 1.3.3 September 1, 2016 45 | 46 | * Fix #383 Service manager fails to start if /etc/docker/ca.pem doesn't 47 | exist @alexeykazakov 48 | 49 | [[v1.3.2-aug-31-2016]] 50 | == 1.3.2 August 31, 2016 51 | 52 | * Fix #384 don't execute os_variant for unsupported box @budhrg 53 | 54 | [[v1.3.1-aug-25-2016]] 55 | == 1.3.1 August 25, 2016 56 | 57 | * Fix #257 proper error message on restarting a stopped service @budhrg 58 | * Fix #379 Success message after vagrant up for Kubernetes @budhrg 59 | 60 | [[v1.3.0-aug-12-2016]] 61 | == 1.3.0 August 12, 2016 62 | 63 | * Fix #374 Fix kubernetes acceptance test @budhrg 64 | * Fix #372 Detect already downloaded oc binary in Windows @budhrg 65 | * Add fix for kubectl download in Windows @budhrg 66 | * Fix #11 Show Kubernetes setup info for use with kubectl @budhrg 67 | * Added unit and acceptance test for kubernetes @budhrg 68 | * Enabled kubernetes from Vagrantfile configuration option @budhrg 69 | * Fix #350 install-cli support for kubernetes @budhrg 70 | * Fix #360 install-cli for docker and openshift in CDK @budhrg 71 | 72 | [[v1.2.2-aug-04-2016]] 73 | == 1.2.2 August 04, 2016 74 | 75 | * Fix #365 undefined method `captures' for nil:NilClass @budhrg 76 | * Fix #348 Handle 302 redirection in install-cli URL validation @budhrg 77 | * Adding docs about using Cucumber tags @hferentschik 78 | * Fix #357 Unable to download cli if user used latest tag or a 79 | alpha/beta tag @budhrg 80 | * Fix #358 Adding reference to ADB installation documentation 81 | @hferentschik 82 | * Fix #352 Create ISSUE_TEMPLATE.MD @budhrg 83 | 84 | [[v1.2.1-jul-15-2016]] 85 | == 1.2.1 July 15, 2016 86 | 87 | * Fix #343 Updated CHANGELOG for user name @budhrg 88 | * Fix #330 Documenting release process @hferentschik 89 | * Fix #313 Explicitly requiring rubyzip as dependency in gemspec 90 | @hferentschik 91 | * Fix #336 Link commands.adoc @budhrg 92 | * Fix #197 Created new doc for available commands with examples 93 | @Preeticp 94 | 95 | [[v1.2.0-jul-14-2016]] 96 | == 1.2.0 July 14, 2016 97 | 98 | * Fix #331 Updating test expectation after latest ADB release 99 | @hferentschik 100 | * Fix #207 Removes SPEC file from repository and reference from README 101 | @navidshaikh 102 | * Fix #321 Adding support for HTTPS URLs for download URLs @budhrg 103 | * Fix #323 Adding note about CLI default download location @navidshaikh 104 | * Fix #312 Improving test for install-cli of Kubernetes @hferentschik 105 | * Fix #312 Adding message to install-cli to indicate that Kubernetes is 106 | not supported by this command @budhrg 107 | * Fix #93 Adding Rubocop configuration @hferentschik 108 | * Fix #90, #196 and #289 Introducing unit tests using minitest @budhrg 109 | * Fix #90 Add install-cli command @budhrg 110 | * Fix #281 Making download of box file a true dependency of the feature 111 | task with update checks @hferentschik 112 | * Fix #20 Adding documentation about the Docker TLS certification 113 | creation @hferentschik 114 | * Fix #291 Reorganized the Available Commands section @preeticp 115 | * Fix #285 Native methods to detect host platform @budhrg 116 | * Fix #287 Removed Unnecessary TODO file @budhrg 117 | * Fix #288 Adding build status image to README @hferentschik 118 | * Fix #278 Acceptance tests for --help option for commands like box, env 119 | and service-operations @budhrg 120 | * Fix #275 Fixes typo in vagrant service-manager --help output 121 | @navidshaikh 122 | * Fix #272 README fix for env default behavior @budhrg 123 | * Fix #262 Updating CI config @hferentschik 124 | * Fix #270 Fix DOCKER_API_VERSION properly on Windows @budhrg 125 | * Fix #268 Explicitly setting v1.8.4 as dev version for Vagrant as HEAD 126 | has switched to Ruby 2.2 @hferentschik 127 | * Fix #252 Added --script-readable option to box ip @budhrg 128 | 129 | [[v1.1.0-jun-08-2016]] 130 | == 1.1.0 June 08, 2016 131 | 132 | * Updated README to make Installation Instructions clearer @bexelbie 133 | * Fix #195: Adding Cucumber and Aruba based acceptance tests 134 | @hferentschik 135 | * CHANGELOG fix and README update for OS support for tests @budhrg 136 | * Fix #220: Bypass hook if no supported guest/box found @budhrg 137 | * Issue #212 Updating the CONTRIBUTING page with latest guidelines 138 | @hferentschik 139 | * Fix #188: Name of k8s service not consistent @budhrg 140 | * Fix #225: service-manager env throws NameError @budhrg 141 | * Fix #168: Extend --debug flag to show plugin activity @budhrg 142 | * Fixed help messages for box and status commands @budhrg 143 | * Don't set private network for unsupported box @budhrg 144 | * Convert CONTRIBUTING and README docs to AsciiDoc @bexelbie 145 | * Fix #235: Unable to access docker daemon from host @budhrg 146 | * Fix #172: Implement "start/enable" service command @budhrg 147 | * Issue #172 Modifying Rake CDK download task to allow downloading 148 | latest nightly build @hferentschik 149 | * Pre-release v1.1.0.beta.1 @navidshaikh 150 | * Fix #237: README and CONTRIBUTING should make use of Asciidoc's :toc: 151 | feature @hferentschik 152 | * Fix #230: Improve acceptance test run time @hferentschik 153 | * Fix #214: Update acceptance tests to support Mac OS without installing 154 | Libvirt @hferentschik 155 | * Fix #247: Moved status test into service-operation @hferentschik 156 | * Issue #211 Adding configuration for CI build @hferentschik 157 | * Fix #210: Adds docker registry URL in openshift env info @navidshaikh 158 | * Fix #250: status throws error with invalid service name @budhrg 159 | * vagrant-service-manager release=1.1.0 version=1 @navidshaikh 160 | 161 | [[v1.0.2-may-09-2016]] 162 | == 1.0.2 May 09, 2016 163 | 164 | * Add --script-readable to env and env docker @bexelbie 165 | * Fix #178: Add status command and separate status from env @bexelbie 166 | * Fix #173: Shows if kubernetes services is running in the box 167 | @navidshaikh 168 | * Fix #169: Adds command for displaying box routable IP address 169 | @navidshaikh 170 | * Fix message for box command on default help @budhrg 171 | * Fix #184: Make env headers comments for vagrant service-manager env 172 | @bexelbie 173 | * Fix #135: Refactor command.rb to make commands easier to add/maintain 174 | @budhrg 175 | * Adds @budhrg as co-maintainer for the plugin @navidshaikh 176 | * Fix #191: 'vagrant service-manager restart' not handled correctly 177 | @budhrg 178 | * Fixes #187, Updated commands in the Available Commands section 179 | @preeticp 180 | * Fix #200: Simplify the eval hint for `vagrant service-manager env` 181 | command @budhrg 182 | * Add environment variables for Openshift env output @bexelbie 183 | * Fix #181: vagrant-service-manager version 1.0.2 release @navidshaikh 184 | 185 | [[v1.0.1-apr-12-2016]] 186 | == 1.0.1 April 12, 2016 187 | 188 | * Updated SPEC (v1.0.0) for url, date and format @budhrg 189 | * Added Table of Contents for README @bexelbie 190 | * Fix #160: "vagrant service-manager restart openshift" not working as 191 | expected @budhrg 192 | * Fix #166: For CDK box, provisioners are not executed by default on 193 | Vagrant up @budhrg 194 | * Fix #170: vagrant-service-manager version 1.0.1 release @navidshaikh 195 | 196 | [[v1.0.0-apr-07-2016]] 197 | == 1.0.0 April 07, 2016 198 | 199 | * Fix #132: vagrant-service-manager 1.0.0 release @navidshaikh 200 | * Fix #133: Adds restart command for services @navidshaikh 201 | * Fix #152: Makes plugin backward compatible with docker 1.8.2 for 202 | docker version API @navidshaikh 203 | * Fix #150: Adds .gitattributes to fix the CHANGELOG.md merge conflicts 204 | @bexelbie 205 | * Fix #142: Removes # before human readable output of openshift env info 206 | @navidshaikh 207 | * Fix #75 and #141: Improves `vagrant service-manager env` output 208 | @navidshaikh 209 | * Fix#146: Updates docker 1.9.1 API call for `docker version` 210 | @navidshaikh 211 | * Updating CONTRIBUTING with note about entry loc @bexelbie 212 | * Update IP detection routine and fix for libvirt @bexelbie 213 | * Fix #50: Add --help @budhrg 214 | * Fix #89: Improve help output for service-manager -h @budhrg 215 | * Vagrant way of showing information using 'locale' @budhrg 216 | * cygwin eval hint now removes colors and env uses export @bexelbie 217 | * Fix #131: Fixes starting OpenShift service by default for CDK box 218 | @navidshaikh 219 | 220 | [[v0.0.5-mar-29-2016]] 221 | == 0.0.5 March 29, 2016 222 | 223 | * Fix #127: vagrant-service-manager 0.0.5 release @navidshaikh 224 | * Fixes a logical issue in the method invocation @navidshaikh 225 | * Fix #122: Certs copied at the time of generation @budhrg 226 | * Fix #121: Removes DOCKER_MACHINE_NAME from `env docker` command output 227 | @navidshaikh 228 | * Fix #65: Adds --script-readable option for `env openshift` command 229 | @navidshaikh 230 | * Fix #80: Check for correct TLS certs pair @budhrg 231 | * Fix #113: Adds DOCKER_API_VERSION in env docker output @navidshaikh 232 | * Adds SPEC file version 0.0.4 of the plugin @navidshaikh 233 | 234 | [[v0.0.4-mar-14-2016]] 235 | 0.0.4 March 14, 2016 236 | 237 | * Fix #101: vagrant-service-manager version 0.0.4 release @navidshaikh 238 | * Remove manually scp for TLS keys and use machine.communicate.download 239 | @bexelbie 240 | * Fix #87 #83: Supports starting OpenShift service as part of config 241 | @budhrg @bexelbie @navidshaikh 242 | * Fix #95: Update hook code to call other middleware first @bexelbie 243 | * Fix #94: Do not exit if box is not supported @navidshaikh 244 | * Fixed missing word for plugin installation in README @budhrg 245 | * Fix #91: Renaming the method name flavor to os_variant 246 | @lalatendumohanty 247 | * Fix links, typos, formatting in CONTRIBUTING.md @budhrg 248 | * Fix #16 and #72: Enable private networking for VirtualBox if not set 249 | @budhrg 250 | 251 | [[v0.0.3-mar-01-2016]] 252 | == 0.0.3 March 01, 2016 253 | 254 | * Fix #74: vagrant-service-manager plugin version 0.0.3 release 255 | @navidshaikh 256 | * Fix #12 and #21: Restart docker service on 'vagrant up' @budhrg 257 | * Update CONTRIBUTING.md and README.md @bexelbie 258 | * Fix #45: Adds exit status for commands and invalid commands 259 | @navidshaikh 260 | * Enhanced the developer instructions for developing the plugin in 261 | README @budhrg 262 | * Updated box versioning info @budhrg 263 | * Fix #45: Adds exit status for commands and invalid commands 264 | @navidshaikh 265 | * Renames the option machine-readable to script-readable @navidshaikh 266 | * Fix #63: Adds --machine-readable option to box version command 267 | @navidshaikh 268 | * Fix #66: Fixing gem build warning @lalatendumohanty 269 | * Adds the filename as class constant @navidshaikh 270 | * Fix #8: Adds subcommand for printing box version 271 | * Fix #59: Prints the error message on stderr @navidshaikh 272 | * Updates openshift connection information output @navidshaikh 273 | * Extends help command with openshift example @navidshaikh 274 | * Adds method to find if a service is running @navidshaikh 275 | * Fix #23: Adds subcommand for displaying openshift information 276 | @navidshaikh 277 | * Updates output docker info in README @navidshaikh 278 | 279 | [[v0.0.2-feb-17-2016]] 280 | == 0.0.2 February 17, 2016 281 | 282 | * Fixes #53: Prep for version v0.0.2 283 | * Fixes #41: Plugin reports to bring up machine for even help command 284 | @navidshaikh 285 | * Updates CHANGELOG.md @navidshaikh 286 | * Fix #41: Fixes the check for finding vagrant box state @navidshaikh 287 | * Adding a version.rb @lalatendumohanty 288 | * Adding steps to build the plugin using Bundler @lalatendumohanty 289 | * Update README with quick start steps @navidshaikh 290 | * Fixes #31: Private key wasn't being sourced for libvirt @bexelbie 291 | * Add notice when copying certificates @bexelbie 292 | * `vagrant service-manager env` return all info @bexelbie 293 | * Fix #4 and #5: Add running machine detection @bexelbie 294 | * Adding objective to the README @lalatendumohanty 295 | * Adds links to gemfile and copr build @navidshaikh 296 | * Adds SPEC file for version 0.0.1 release @navidshaikh 297 | 298 | [[v0.0.1-feb-09-2016]] 299 | == 0.0.1 February 09, 2016 300 | 301 | * Updates the source git repository URL 302 | * Restructure the lib directory and sources plugin from module 303 | * Removes unused vagrant password from repository 304 | * Uses net/scp module instead of scp command 305 | * Adds a sub-command for configuring docker daemon 306 | vagrant-service-manager env docker 307 | * Ports equivalent functionality of plugin for 308 | https://github.com/projectatomic/vagrant-adbinfo 309 | * Renames the plugin and update the rest of repository 310 | 311 | @navidshaikh @bexelbie 312 | 313 | _Plugin is forked and extended from 314 | https://github.com/projectatomic/vagrant-adbinfo[vagrant-adbinfo]._ 315 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = vagrant-service-manager 2 | :toc: 3 | :toc-placement!: 4 | 5 | The vagrant-service-manager plugin is designed to enable 6 | easier access to the features and services provided by the 7 | https://github.com/projectatomic/adb-atomic-developer-bundle[Atomic 8 | Developer Bundle (ADB)]. It provides setup information, including 9 | environment variables and certificates, required to access services 10 | provided by the ADB and is a must have for most ADB users. + 11 | + 12 | This plugin makes it easier to use the ADB with host-based tools such as 13 | Eclipse and the docker and kubernetes CLI commands. Details on how to 14 | use ADB with this plugin can be found in the 15 | https://github.com/projectatomic/adb-atomic-developer-bundle/blob/master/docs/using.adoc[ADB 16 | Documentation]. 17 | 18 | ''' 19 | toc::[] 20 | ''' 21 | 22 | == Status 23 | 24 | [[img-build-status]] 25 | image::https://ci.centos.org/buildStatus/icon?job=vagrant-service-manager[link="https://ci.centos.org/job/vagrant-service-manager"] 26 | 27 | == Installation 28 | 29 | The vagrant-service-manager plugin is distributed as a Ruby Gem. 30 | The https://rubygems.org/gems/vagrant-service-manager[gem] is available on 31 | https://rubygems.org[RubyGems] and can be installed via the standard 32 | Vagrant plugin installation method: 33 | 34 | ------------------------------------------------ 35 | $ vagrant plugin install vagrant-service-manager 36 | ------------------------------------------------ 37 | 38 | NOTE: To resolve any issues with the plugin installation and for more information on how to install Vagrant on various systems, refer to the 39 | https://github.com/projectatomic/adb-atomic-developer-bundle/blob/master/docs/installing.adoc[ADB installation instructions]. 40 | 41 | == Usage 42 | 43 | === Example execution of the plugin 44 | 45 | 1. Install vagrant-service-manager plugin: 46 | + 47 | ---------------------------------------------- 48 | vagrant plugin install vagrant-service-manager 49 | ---------------------------------------------- 50 | 51 | 1. Download the relevant Vagrantfile for your 52 | https://github.com/projectatomic/adb-atomic-developer-bundle[ADB] 53 | vagrant box, from the 54 | https://github.com/projectatomic/adb-atomic-developer-bundle/tree/master/components/centos[repository]. 55 | For further details on the usage of custom Vagrantfiles designed for 56 | specific use cases, refer to the Download ADB section in the 57 | https://github.com/projectatomic/adb-atomic-developer-bundle/blob/master/docs/installing.adoc[Installing ADB] Documentation. 58 | 59 | 1. Start the ADB vagrant box using `vagrant up`. For detailed 60 | instructions consult the 61 | https://github.com/projectatomic/adb-atomic-developer-bundle/blob/master/docs/installing.adoc[Installation 62 | Documentation]. 63 | + 64 | NOTE: When the vagrant-service-manager plugin is loaded and an ADB box is 65 | started using the VirtualBox provider, the user needs to add a routable 66 | non NAT network interface declaration in the Vagrantfile. If the user 67 | does not provide a network declaration in the Vagrantfile, a private 68 | DHCP network is added by default and a warning is displayed. 69 | 70 | 1. Run the plugin to get the environment variables and certificates: 71 | + 72 | ---------------------------------------------------------------------------- 73 | $ vagrant service-manager env docker 74 | # Set the following environment variables to enable access to the 75 | # docker daemon running inside of the vagrant virtual machine: 76 | export DOCKER_HOST=tcp://172.28.128.182:2376 77 | export DOCKER_CERT_PATH=/foo/bar/.vagrant/machines/default/virtualbox/docker 78 | export DOCKER_TLS_VERIFY=1 79 | export DOCKER_API_VERSION=1.20 80 | 81 | # run following command to configure your shell: 82 | # eval "$(vagrant service-manager env docker)" 83 | ---------------------------------------------------------------------------- 84 | + 85 | NOTE: The required TLS certificates are copied to the host machine at 86 | the time of `vagrant up` itself. Every run of 87 | `vagrant service-manager env docker` checks for the validity of the 88 | certificates on the host machine by matching the certificates inside the 89 | VM. If the certificates on the host machine are invalid, this command 90 | will also re-download the certificates onto the host machine. 91 | 92 | === Available commands 93 | 94 | For a detailed list of all available commands and their explanations refer 95 | to the link:commands.adoc[Commands Document]. + 96 | The following section lists the high level commands available for the plugin. 97 | which enable you to set up your environment variables and get the TLS 98 | certificates to secure the Docker communication channel; identify the 99 | routable ip address as well as the version of your VM and manage the life 100 | cycle of the configured services. 101 | 102 | - `vagrant service-manager [command] [--help | -h]` + 103 | Displays the possible commands, options and other relevant information 104 | for the vagrant-service-manager plugin. 105 | 106 | - `vagrant service-manager env [service] [--script-readable]` + 107 | Displays connection information for all active services in the VM, in a 108 | manner that can be evaluated in a shell. 109 | 110 | - `vagrant service-manager box [command] [--script-readable]` + 111 | Displays VM related information like release version, IP, etc. 112 | 113 | - `vagrant service-manager [operation] [service]` + 114 | Manages the life cycle of a service. 115 | 116 | - `vagrant service-manager install-cli [service]` + 117 | Installs the client binary for the specified service. 118 | 119 | [[debug-flag]] 120 | ==== Debug Flag 121 | 122 | Append `--debug` flag to enable debug mode. 123 | 124 | NOTE: Debug output from `vagrant-service-manager` is prepended with 125 | the following string: 126 | `DEBUG command: [ service-manager: ]` 127 | 128 | === Exit codes 129 | 130 | The following table lists the plugin's exit codes and their meaning: 131 | 132 | [cols=",",options="header",] 133 | |======================================================================= 134 | |Exit Code Number |Meaning 135 | |`0` |No error 136 | 137 | |`1` |Catch all for general errors / Wrong sub-command or option given 138 | 139 | |`3` |Vagrant box is not running and should be running for this command 140 | to succeed 141 | 142 | |`126` |A service inside the box is not running / Command invoked cannot 143 | execute 144 | |======================================================================= 145 | 146 | === IP address detection 147 | 148 | There is no standardized way of detecting Vagrant box IP addresses. This 149 | code uses the last IPv4 address available from the set of configured 150 | addresses that are _up_. i.e. if eth0, eth1, and eth2 are all up and 151 | have IPv4 addresses, the address on eth2 is used. 152 | 153 | === HTTP Proxy Settings 154 | 155 | In an environment where the HTTP traffic needs to pass through an 156 | HTTP proxy server, set the `proxy`, `proxy_user` and 157 | `proxy_password` proxy configurations in the Vagrantfiles to enable 158 | services like Docker and OpenShift to function correctly. + 159 | You can do so via: 160 | + 161 | ----- 162 | config.servicemanager.proxy = "" 163 | config.servicemanager.proxy_user = "" 164 | config.servicemanager.proxy_password = "" 165 | ----- 166 | 167 | When these settings are applied, they are passed through to the Docker and OpenShift services. In an unauthenticated proxy environment, the `proxy_user` and `proxy_password` configurations can be omitted. 168 | 169 | NOTE: `http_proxy`, `http_proxy_user` and `http_proxy_password` have been depreacted now. 170 | 171 | === Configuring Services 172 | The vagrant-service-manager helps you configure the service of your choice: 173 | 174 | . Enable the desired service(s) in the ADB Vagrantfile as: 175 | + 176 | `config.servicemanager.services = "openshift"` 177 | + 178 | [NOTE] 179 | ==== 180 | - Docker is the default service for the Atomic Developer Bundle and does not require any configuration to ensure it is started whereas, the Red Hat Enterprise Linux Container Development Kit, which is based on ADB, automatically starts OpenShift. + 181 | - You can use a comma-separated list to enable multiple services. For instance: docker, openshift. 182 | ==== 183 | 184 | . Enable the relevant option for the services you have selected in the Vagrantfile. For example, specific versions of OpenShift can be set using the following variables: 185 | + 186 | 187 | - `config.servicemanager.openshift_docker_registry = "docker.io"` - Specifies the registry from where the OpenShift image is pulled. 188 | + 189 | - `config.servicemanager.openshift_image_name = "openshift/origin"` - Specifies the image to be used. 190 | + 191 | - `config.servicemanager.openshift_image_tag = "v1.3.0"` - Specifies the version of the image to be used. 192 | 193 | 194 | == Development 195 | 196 | === Setup 197 | 198 | 1. After cloning the repository, install the http://bundler.io/[Bundler] 199 | gem: 200 | + 201 | --------------------- 202 | $ gem install bundler -v 1.12.5 203 | --------------------- 204 | + 205 | NOTE: You need to specify version 1.12.5. It will not work with the latest version of Bundler. 206 | 207 | 208 | 1. Then setup your project dependencies: 209 | + 210 | ---------------- 211 | $ bundle install 212 | ---------------- 213 | 214 | 1. The build is driven via `rake`. All build related tasks should be executed 215 | in the Bundler environment, for example `bundle exec rake clean`. You can get a 216 | list of available Rake tasks via: 217 | + 218 | --------------------- 219 | $ bundle exec rake -T 220 | --------------------- 221 | 222 | === Code style 223 | 224 | As most other open-source projects, vagrant-service-manager has a set of conventions 225 | about how to write code for it. It follows the 226 | https://github.com/bbatsov/ruby-style-guide[Ruby Style Guide]. 227 | 228 | You can verify that your changes adhere to this style using the 229 | http://batsov.com/rubocop[RuboCop] Rake task: 230 | 231 | -------------------------- 232 | $ bundle exec rake rubocop 233 | -------------------------- 234 | 235 | === Unit tests 236 | 237 | The source contains a set of http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html[Minitest] 238 | unit tests. They can be run as follows: 239 | 240 | To run the entire test suite: 241 | 242 | ------------------------ 243 | $ bundle exec rake test 244 | ------------------------ 245 | 246 | To run a single test: 247 | 248 | ------------------------------------------------- 249 | $ bundle exec rake test TEST= 250 | ------------------------------------------------- 251 | 252 | === Acceptance tests 253 | 254 | The source also contains a set of https://cucumber.io/[Cucumber] 255 | acceptance tests. They can be run via: 256 | 257 | --------------------------- 258 | $ bundle exec rake features 259 | --------------------------- 260 | 261 | You can run a single feature specifying the path to the feature file 262 | to run via the _FEATURE_ environment variable: 263 | 264 | ----------------------------------------------------------------------- 265 | $ bundle exec rake features FEATURE=features/.feature 266 | ----------------------------------------------------------------------- 267 | 268 | NOTE: These Cucumber tests do not run on Windows, pending resolution of 269 | https://github.com/projectatomic/vagrant-service-manager/issues/213[Issue #213]. 270 | 271 | ==== Controlling virtualization provider and box type via _PROVIDER_ and _BOX_ environment variables 272 | 273 | Per default, only the scenarios for ADB in combination with the 274 | VirtualBox provider are run. However, you can also run the tests against CDK 275 | and/or use the Libvirt provider using the environment variables _BOX_ 276 | and _PROVIDER_ respectively: 277 | 278 | ----------------------------------------------------- 279 | # Run tests against CDK using Libvirt 280 | $ bundle exec rake features BOX=cdk PROVIDER=libvirt 281 | 282 | # Run against ADB and CDK (boxes are comma separated) 283 | $ bundle exec rake features BOX=cdk,adb 284 | 285 | # Run against ADB and CDK using VirtualBox and Libvirt 286 | $ bundle exec rake features BOX=cdk,adb PROVIDER=libvirt,virtualbox 287 | ----------------------------------------------------- 288 | 289 | ==== Test boxes 290 | 291 | The _features_ task will transparently download the required Vagrant 292 | boxes and cache them in the _.boxes_ directory. The cache can be cleared 293 | via the _clean_boxes_ task. For implementation details refer to the 294 | https://github.com/projectatomic/vagrant-service-manager/blob/master/Rakefile[Rakefile]. 295 | 296 | Using the variable _NIGHTLY=true_ you can make sure that the 297 | latest nightly build of the CDK is used (VPN access required). 298 | 299 | -------------------------------------------------- 300 | # Uses the latest nightly build of the CDK instead of the latest public release as per developer.redhat.com 301 | $ bundle exec rake features BOX=cdk NIGHTLY=true 302 | -------------------------------------------------- 303 | 304 | NOTE: Per default the latest public release of the CDK is used. 305 | 306 | ==== Cucumber tags 307 | 308 | Some of the scenarios take a long time to run, so in order to keep the 309 | turn-around time on the development machine acceptable, we also make 310 | use of the _@ci-only_ https://github.com/cucumber/cucumber/wiki/Tags[tag]. 311 | 312 | Per default scenarios annotated with _@ci-only_ are only run on the 313 | https://ci.centos.org/job/vagrant-service-manager[CI server]. Also, to run these tests locally, 314 | you need to activate the _all_ profile: 315 | 316 | -------------------------------------------------- 317 | bundle exec rake features CUCUMBER_OPTS='-p all' 318 | -------------------------------------------------- 319 | 320 | For other defined profiles refer to Cucumber config file https://github.com/projectatomic/vagrant-service-manager/blob/master/.config/cucumber.yml[cucumber.yml]. 321 | 322 | ==== Cucumber test reports 323 | 324 | After test execution, the Cucumber test reports can be found under 325 | _build/features_report.html_. They can be opened via: 326 | 327 | --------------------------------------- 328 | $ bundle exec rake features:open_report 329 | --------------------------------------- 330 | 331 | === Asciidoc 332 | 333 | The documentation of this plugin is written in http://asciidoctor.org[Asciidoc]. If you need some syntax help, 334 | refer to the http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[AsciiDoc Syntax Quick Reference]. 335 | 336 | To build the documentation you can execute 337 | 338 | ---- 339 | $ bundle exec rake html 340 | ---- 341 | 342 | which will build the HTML documentation into the folder _build/html_. 343 | 344 | The source code also contains a link:Guardfile[Guardfile] for the https://github.com/guard/guard[Guard] library. 345 | You can execute 346 | 347 | ---- 348 | $ bundle exec guard 349 | ---- 350 | 351 | and your HTML documentation will be automatically updated on each change to an Asciidoc source file. 352 | https://github.com/guard/guard-livereload[Live reload] is also enabled, so you just need to install the right 353 | http://livereload.com/extensions/#installing-sections[LiveReload Safari/Chrome/Firefox extension] and your 354 | browser will refresh the page each time you save a change to your Asciidoc files. 355 | 356 | == Getting involved 357 | 358 | We welcome your input. You can submit issues or pull requests with 359 | respect to the vagrant-service-manager plugin. Refer to the 360 | https://github.com/projectatomic/vagrant-service-manager/blob/master/CONTRIBUTING.adoc[contributing 361 | guidelines] for detailed information on how to contribute to this 362 | plugin. 363 | 364 | You can contact us on: 365 | 366 | * IRC: #atomic and #nulecule on freenode 367 | * Mailing List: container-tools@redhat.com 368 | --------------------------------------------------------------------------------