cyoi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ script: bundle exec rake spec:$SUITE
3
+ rvm:
4
+ - ruby-1.9.3
5
+ # - rbx-19mode
6
+ - ruby-2.0.0
7
+ notifications:
8
+ email:
9
+ recipients:
10
+ - drnicwilliams@gmail.com
11
+ on_success: change
12
+ on_failure: always
13
+ env:
14
+ matrix:
15
+ - SUITE=unit
16
+ global:
17
+ - secure: ""
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cyoi.gemspec
4
+ gemspec
5
+
6
+ gem "settingslogic", github: "drnic/settingslogic", branch: "integration"
7
+
8
+ group :development do
9
+ gem "awesome_print"
10
+ gem "rb-fsevent", "~> 0.9.1"
11
+ gem "guard-rspec"
12
+ end
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec})
3
+ watch(%r{^lib/cyoi}) { |m| "spec" }
4
+ # watch(%r{^lib/cyoi/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
5
+ end
6
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dr Nic Williams
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # Choose Your Own Infrastructure
2
+
3
+ A library to ask an end-user to choose an infrastructure (AWS, OpenStack, etc), region, and login credentials.
4
+
5
+ This library was extracted from [inception-server](https://github.com/drnic/inception-server) for reuse by [bosh-bootstrap](https://github.com/StarkAndWayne/bosh-bootstrap). It might also be useful to your own CLI applications that need to ask a user to give you their infrastructure credentials/region so your application can control their infrastructure (say via [fog](http://fog.io)).
6
+
7
+ [![Build Status](https://travis-ci.org/drnic/cyoi.png?branch=master)](https://travis-ci.org/drnic/cyoi)
8
+ [![Code Climate](https://codeclimate.com/github/drnic/cyoi.png)](https://codeclimate.com/github/drnic/cyoi)
9
+
10
+ When you use the library, your application will attempt to guess what infrastructure/credentials the user will use (via `~/.fog`) and then fall back to prompting for remaining information:
11
+
12
+ ```
13
+ Auto-detected infrastructure API credentials at ~/.fog (override with $FOG)
14
+ 1. AWS (default)
15
+ 2. AWS (starkandwayne)
16
+ 3. Alternate credentials
17
+ Choose infrastructure: 3
18
+
19
+ 1. AWS
20
+ 2. OpenStack
21
+ Choose infrastructure: 1
22
+
23
+
24
+ Using provider aws:
25
+
26
+ 1. *US East (Northern Virginia) Region (us-east-1)
27
+ 2. US West (Oregon) Region (us-west-2)
28
+ 3. US West (Northern California) Region (us-west-1)
29
+ 4. EU (Ireland) Region (eu-west-1)
30
+ 5. Asia Pacific (Singapore) Region (ap-southeast-1)
31
+ 6. Asia Pacific (Sydney) Region (ap-southeast-2)
32
+ 7. Asia Pacific (Tokyo) Region (ap-northeast-1)
33
+ 8. South America (Sao Paulo) Region (sa-east-1)
34
+ Choose AWS region: 2
35
+
36
+ Access key: KEYGOESHERE
37
+ Secret key: SECRETGOESHERE
38
+
39
+ Confirming: Using aws/us-west-2
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ```
45
+ ```
46
+
47
+ ## Installation
48
+
49
+ Add this line to your application's Gemfile:
50
+
51
+ ```
52
+ gem "cyoi"
53
+ gem "settingslogic", github: "drnic/settingslogic", branch: "integration"
54
+ ```
55
+
56
+ NOTE: The `settingslogic` fork is necessary for some unmerged/unreleased extensions.
57
+
58
+ And then execute:
59
+
60
+ ```
61
+ $ bundle
62
+ ```
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create new Pull Request
71
+ 6. Send [@drnic](https://github.com/drnic) a big bag of Doritos
@@ -0,0 +1,26 @@
1
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
2
+
3
+ require "rubygems"
4
+ require "bundler"
5
+ Bundler.setup(:default, :test, :development)
6
+
7
+ require "bundler/gem_tasks"
8
+
9
+ require "rake/dsl_definition"
10
+ require "rake"
11
+ require "rspec/core/rake_task"
12
+
13
+ if defined?(RSpec)
14
+ namespace :spec do
15
+ desc "Run Unit Tests"
16
+ unit_rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
17
+ t.pattern = "spec/unit/**/*_spec.rb"
18
+ t.rspec_opts = %w(--format progress --color)
19
+ end
20
+ end
21
+
22
+ desc "Run tests"
23
+ task :spec => %w(spec:unit)
24
+ end
25
+
26
+ task :default => ["spec"]
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.dirname(__FILE__) + '/../lib'
3
+
4
+ require "rubygems"
5
+ require "cyoi/cli/provider"
6
+
7
+ # interface assumed by aruba in-process testing
8
+ # https://github.com/cucumber/aruba#testing-ruby-cli-programs-without-spawning-a-new-ruby-process
9
+ Cyoi::Cli::Provider.new(ARGV.dup).execute!
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cyoi/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cyoi"
8
+ spec.version = Cyoi::VERSION
9
+ spec.authors = ["Dr Nic Williams"]
10
+ spec.email = ["drnicwilliams@gmail.com"]
11
+ spec.description = "A library to ask an end-user to choose an infrastructure (AWS, OpenStack, etc), region, and login credentials."
12
+ spec.summary = <<-README
13
+ A library to ask an end-user to choose an infrastructure (AWS, OpenStack, etc), region, and login credentials.
14
+
15
+ This library was extracted from [inception-server](https://github.com/drnic/inception-server) for reuse by [bosh-bootstrap](https://github.com/StarkAndWayne/bosh-bootstrap). It might also be useful to your own CLI applications that need to ask a user to give you their infrastructure credentials/region so your application can control their infrastructure (say via [fog](http://fog.io)).
16
+ README
17
+ spec.homepage = "https://github.com/drnic/cyoi"
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files`.split($/)
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "highline", "~> 1.6"
26
+ spec.add_dependency "settingslogic", "~> 2.0.9" # need to_nested_hash method
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.3"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "rspec"
31
+ spec.add_development_dependency "aruba"
32
+ end
@@ -0,0 +1,5 @@
1
+ module Cyoi
2
+ end
3
+
4
+ require "cyoi/version"
5
+
@@ -0,0 +1,3 @@
1
+ require "cyoi"
2
+ module Cyoi::Cli
3
+ end
@@ -0,0 +1,51 @@
1
+ module Cyoi; module Cli; module AutoDetection; end; end; end
2
+
3
+ require "cyoi/cli/auto_detection/auto_detection_fog"
4
+
5
+ class Cyoi::Cli::AutoDetection::UI
6
+ attr_reader :attributes
7
+ attr_reader :hl
8
+
9
+ def initialize(attributes, highline)
10
+ @hl = highline
11
+ @attributes = attributes.is_a?(Hash) ? Settingslogic.new(attributes) : attributes
12
+ raise "@attributes must be Settingslogic (or Hash)" unless @attributes.is_a?(Settingslogic)
13
+ end
14
+
15
+ def perform
16
+ # Display menu of choices
17
+ # Include "Alternate credentials" as the last option
18
+ if aggregated_detector_choices.keys.size > 0
19
+ hl.choose do |menu|
20
+ menu.prompt = "Choose an auto-detected infrastructure: "
21
+ aggregated_detector_choices.each do |label, credentials|
22
+ menu.choice(label) do
23
+ attributes.set("name", credentials.delete("name"))
24
+ attributes.set("credentials", credentials)
25
+ end
26
+ end
27
+ menu.choice("Alternate credentials") { false }
28
+ end
29
+ end
30
+ end
31
+
32
+ # helper to export the complete nested attributes.
33
+ def export_attributes
34
+ attributes.to_nested_hash
35
+ end
36
+
37
+ def aggregated_detector_choices
38
+ @aggregated_detector_choices ||= begin
39
+ detectors.inject({}) do |choices, detector_class|
40
+ detector = detector_class.new
41
+ choices.merge!(detector.auto_detection_choices)
42
+ end
43
+ end
44
+ end
45
+
46
+ def detectors
47
+ [
48
+ Cyoi::Cli::AutoDetection::AutoDetectionFog
49
+ ]
50
+ end
51
+ end
@@ -0,0 +1,96 @@
1
+ module Cyoi; module Cli; module AutoDetection; end; end; end
2
+
3
+ class Cyoi::Cli::AutoDetection::AutoDetectionFog
4
+ # Displays a prompt for known IaaS that are configured
5
+ # within .fog config file if found.
6
+ #
7
+ # If no ~/.fog file found or user chooses "Alternate credentials"
8
+ # then no changes are made to settings.
9
+ #
10
+ # For example:
11
+ #
12
+ # 1. AWS (default)
13
+ # 2. AWS (bosh)
14
+ # 3. Alternate credentials
15
+ # Choose infrastructure: 1
16
+ #
17
+ # If .fog config only contains one provider, do not prompt.
18
+ #
19
+ # fog config file looks like:
20
+ # :default:
21
+ # :aws_access_key_id: PERSONAL_ACCESS_KEY
22
+ # :aws_secret_access_key: PERSONAL_SECRET
23
+ # :bosh:
24
+ # :aws_access_key_id: SPECIAL_IAM_ACCESS_KEY
25
+ # :aws_secret_access_key: SPECIAL_IAM_SECRET_KEY
26
+ #
27
+ # Convert this into:
28
+ # { "AWS (default)" => {:aws_access_key_id => ...}, "AWS (bosh)" => {...} }
29
+ #
30
+ # Then display options to user to choose.
31
+ #
32
+ # Currently detects following fog providers:
33
+ # * AWS
34
+ # * OpenStack
35
+ #
36
+ # If "Alternate credentials" is selected, then user is prompted for fog
37
+ # credentials:
38
+ # * provider?
39
+ # * access keys?
40
+ # * API URI or region?
41
+ #
42
+ # Sets (unless 'Alternate credentials' is chosen)
43
+ # * settings.provider.name
44
+ # * settings.provider.credentials
45
+ #
46
+ # For AWS, the latter has keys:
47
+ # {:aws_access_key_id, :aws_secret_access_key}
48
+ #
49
+ # For OpenStack, the latter has keys:
50
+ # {:openstack_username, :openstack_api_key, :openstack_tenant
51
+ # :openstack_auth_url, :openstack_region }
52
+ def auto_detection_choices
53
+ fog_choices = {}
54
+ # Prepare menu options:
55
+ # each provider/profile name gets a menu choice option
56
+ fog_config.inject({}) do |iaas_options, fog_profile|
57
+ profile_name, profile = fog_profile
58
+ if profile[:aws_access_key_id]
59
+ fog_choices["AWS (#{profile_name})"] = {
60
+ "name" => "aws",
61
+ "provider" => "AWS",
62
+ "aws_access_key_id" => profile[:aws_access_key_id],
63
+ "aws_secret_access_key" => profile[:aws_secret_access_key]
64
+ }
65
+ end
66
+ if profile[:openstack_username]
67
+ fog_choices["OpenStack (#{profile_name})"] = {
68
+ "name" => "openstack",
69
+ "provider" => "OpenStack",
70
+ "openstack_username" => profile[:openstack_username],
71
+ "openstack_api_key" => profile[:openstack_api_key],
72
+ "openstack_tenant" => profile[:openstack_tenant],
73
+ "openstack_auth_url" => profile[:openstack_auth_url],
74
+ "openstack_region" => profile[:openstack_region]
75
+ }
76
+ end
77
+ end
78
+ fog_choices
79
+ end
80
+
81
+ def fog_config
82
+ @fog_config ||= begin
83
+ if File.exists?(File.expand_path(fog_config_path))
84
+ puts "Auto-detected infrastructure API credentials at #{fog_config_path} (override with $FOG)"
85
+ YAML.load_file(File.expand_path(fog_config_path))
86
+ else
87
+ {}
88
+ end
89
+ end
90
+ end
91
+
92
+ def fog_config_path
93
+ ENV['FOG'] || "~/.fog"
94
+ end
95
+
96
+ end
@@ -0,0 +1,10 @@
1
+ module Cyoi::Cli::Helpers
2
+ end
3
+
4
+ require "cyoi/cli/helpers/interactions"
5
+ require "cyoi/cli/helpers/settings"
6
+
7
+ module Cyoi::Cli::Helpers
8
+ include Cyoi::Cli::Helpers::Interactions
9
+ include Cyoi::Cli::Helpers::Settings
10
+ end
@@ -0,0 +1,15 @@
1
+ require "highline"
2
+
3
+ module Cyoi::Cli::Helpers::Interactions
4
+ def cyan; "\033[36m" end
5
+ def clear; "\033[0m" end
6
+ def bold; "\033[1m" end
7
+ def red; "\033[31m" end
8
+ def green; "\033[32m" end
9
+ def yellow; "\033[33m" end
10
+
11
+ # Helper to access HighLine for ask & menu prompts
12
+ def hl
13
+ @hl ||= HighLine.new(@stdin, @stdout)
14
+ end
15
+ end
@@ -0,0 +1,45 @@
1
+ require "settingslogic"
2
+ require "fileutils"
3
+
4
+ module Cyoi::Cli::Helpers::Settings
5
+ include FileUtils
6
+
7
+ # The base directory for holding the manifest settings file
8
+ # and private keys
9
+ #
10
+ # Defaults to ~/.bosh_inception; and can be overridden with either:
11
+ # * $SETTINGS - to a folder (supported method)
12
+ def settings_dir
13
+ @settings_dir ||= ENV['SETTINGS'] || raise("please assign @settings_dir or $SETTINGS first")
14
+ end
15
+
16
+ def settings_ssh_dir
17
+ File.join(settings_dir, "ssh")
18
+ end
19
+
20
+ def settings_path
21
+ @settings_path ||= File.join(settings_dir, "settings.yml")
22
+ end
23
+
24
+ def settings
25
+ @settings ||= begin
26
+ unless File.exists?(settings_path)
27
+ mkdir_p(settings_dir)
28
+ File.open(settings_path, "w") { |file| file << "--- {}" }
29
+ end
30
+ chmod(0600, settings_path)
31
+ chmod(0700, settings_ssh_dir) if File.directory?(settings_ssh_dir)
32
+ Settingslogic.new(settings_path)
33
+ end
34
+ end
35
+
36
+ # Saves current nested Settingslogic into pure Hash-based YAML file
37
+ # Recreates accessors on Settingslogic object (since something has changed)
38
+ def save_settings!
39
+ File.open(settings_path, "w") { |f| f << settings.to_nested_hash.to_yaml }
40
+ settings.create_accessors!
41
+ end
42
+
43
+ def migrate_old_settings
44
+ end
45
+ end
@@ -0,0 +1,72 @@
1
+ require "cyoi/cli"
2
+ require "cyoi/cli/auto_detection"
3
+ require "cyoi/cli/helpers"
4
+ class Cyoi::Cli::Provider
5
+ include Cyoi::Cli::Helpers
6
+
7
+ def initialize(argv, stdin=STDIN, stdout=STDOUT, stderr=STDERR, kernel=Kernel)
8
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
9
+ @settings_dir = @argv.shift || "/tmp/provider_settings"
10
+ @settings_dir = File.expand_path(@settings_dir)
11
+ end
12
+
13
+ def execute!
14
+ unless valid_infrastructure?
15
+ settings["provider"] ||= {}
16
+ auto_detection unless settings.exists?("provider.name")
17
+ choose_provider unless settings.exists?("provider.name")
18
+ settings["provider"] = provider_cli.perform_and_return_attributes
19
+ save_settings!
20
+ end
21
+ provider_cli.display_confirmation
22
+ end
23
+
24
+ # Continue the interactive session with the user
25
+ # specific to the provider/infrastructure they have
26
+ # chosen.
27
+ #
28
+ # The returned object is a class from cyoi/cli/providers/provier_cli_NAME.rb
29
+ # The class loads itself into `@provider_clis` via `register_provider_cli`
30
+ #
31
+ # Returns nil if settings.provider.name not set
32
+ def provider_cli
33
+ @provider_cli ||= begin
34
+ return nil unless name = settings.exists?("provider.name")
35
+ require "cyoi/cli/providers/provider_cli_#{settings.provider.name}"
36
+ klass = self.class.provider_cli(settings.provider.name)
37
+ klass.new(settings.provider, hl)
38
+ end
39
+ end
40
+
41
+ def self.register_provider_cli(name, klass)
42
+ @provider_clis ||= {}
43
+ @provider_clis[name] = klass
44
+ end
45
+
46
+ def self.provider_cli(name)
47
+ @provider_clis[name]
48
+ end
49
+
50
+ protected
51
+ def valid_infrastructure?
52
+ provider_cli && provider_cli.valid_infrastructure?
53
+ end
54
+
55
+ def auto_detection
56
+ ui = Cyoi::Cli::AutoDetection::UI.new(settings.provider, hl)
57
+ if ui.perform
58
+ settings["provider"] = ui.export_attributes
59
+ save_settings!
60
+ end
61
+ end
62
+
63
+ # Prompts user to pick from the supported regions
64
+ def choose_provider
65
+ settings.provider["name"] = hl.choose do |menu|
66
+ menu.prompt = "Choose your infrastructure: "
67
+ menu.choice("AWS") { "aws" }
68
+ menu.choice("OpenStack") { "openstack" }
69
+ end
70
+ save_settings!
71
+ end
72
+ end
@@ -0,0 +1,32 @@
1
+ module Cyoi; module Cli; module Providers; end; end; end
2
+
3
+ class Cyoi::Cli::Providers::ProviderCli
4
+ attr_reader :attributes
5
+ attr_reader :hl
6
+
7
+ def initialize(attributes, highline)
8
+ @hl = highline
9
+ @attributes = attributes.is_a?(Hash) ? Settingslogic.new(attributes) : attributes
10
+ raise "@attributes must be Settingslogic (or Hash)" unless @attributes.is_a?(Settingslogic)
11
+ end
12
+
13
+ # helper to export the complete nested attributes.
14
+ def export_attributes
15
+ attributes.to_nested_hash
16
+ end
17
+
18
+ # Only a subclass can represent valid infrastruct
19
+ # If using this class directly, then it has not yet decided
20
+ # which provider/infrastructure to use
21
+ def valid_infrastructure?
22
+ false
23
+ end
24
+
25
+ def display_confirmation
26
+ raise "please implement in subclass"
27
+ end
28
+
29
+ def say(message, *args)
30
+ puts(message)
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ require "cyoi/cli/providers/provider_cli"
2
+ class Cyoi::Cli::Providers::ProviderCliAws < Cyoi::Cli::Providers::ProviderCli
3
+ def perform_and_return_attributes
4
+ unless valid_infrastructure?
5
+ puts "\nUsing provider AWS\n"
6
+ setup_credentials
7
+ choose_region
8
+ end
9
+ export_attributes
10
+ end
11
+
12
+ def setup_credentials
13
+ puts "\n"
14
+ attributes.set_default("credentials", {})
15
+ credentials = attributes.credentials
16
+ credentials["aws_access_key_id"] = hl.ask("Access key: ") unless credentials.exists?("aws_access_key_id")
17
+ credentials["aws_secret_access_key"] = hl.ask("Secret key: ") unless credentials.exists?("aws_secret_access_key")
18
+ end
19
+
20
+ def choose_region
21
+ puts "\n"
22
+ hl.choose do |menu|
23
+ menu.prompt = "Choose AWS region: "
24
+ default_menu_item = nil
25
+ region_labels.each do |region_info|
26
+ label, code = region_info[:label], region_info[:code]
27
+ menu_item = "#{label} (#{code})"
28
+ if code == default_region_code
29
+ menu_item = "*#{menu_item}"
30
+ default_menu_item = menu_item
31
+ end
32
+ menu.choice(menu_item) do
33
+ attributes["region"] = code
34
+ end
35
+ end
36
+ menu.default = default_menu_item if default_menu_item
37
+ end
38
+ end
39
+
40
+ def valid_infrastructure?
41
+ attributes.exists?("credentials.aws_access_key_id") &&
42
+ attributes.exists?("credentials.aws_secret_access_key") &&
43
+ attributes.exists?("region")
44
+ end
45
+
46
+ def display_confirmation
47
+ puts "\n"
48
+ puts "Confirming: Using AWS/#{attributes.region}"
49
+ end
50
+
51
+ protected
52
+ # http://docs.aws.amazon.com/general/latest/gr/rande.html#region
53
+ def region_labels
54
+ [
55
+ { label: "US East (Northern Virginia) Region", code: "us-east-1" },
56
+ { label: "US West (Oregon) Region", code: "us-west-2" },
57
+ { label: "US West (Northern California) Region", code: "us-west-1" },
58
+ { label: "EU (Ireland) Region", code: "eu-west-1" },
59
+ { label: "Asia Pacific (Singapore) Region", code: "ap-southeast-1" },
60
+ { label: "Asia Pacific (Sydney) Region", code: "ap-southeast-2" },
61
+ { label: "Asia Pacific (Tokyo) Region", code: "ap-northeast-1" },
62
+ { label: "South America (Sao Paulo) Region", code: "sa-east-1" },
63
+ ]
64
+ end
65
+
66
+ def default_region_code
67
+ "us-east-1"
68
+ end
69
+ end
70
+
71
+ Cyoi::Cli::Provider.register_provider_cli("aws", Cyoi::Cli::Providers::ProviderCliAws)
@@ -0,0 +1,45 @@
1
+ require "cyoi/cli/providers/provider_cli"
2
+ class Cyoi::Cli::Providers::ProviderCliOpenStack < Cyoi::Cli::Providers::ProviderCli
3
+ def perform_and_return_attributes
4
+ unless valid_infrastructure?
5
+ puts "\nUsing provider OpenStack\n"
6
+ setup_credentials
7
+ choose_region
8
+ end
9
+ export_attributes
10
+ end
11
+
12
+ def setup_credentials
13
+ puts "\n"
14
+ attributes.set_default("credentials", {})
15
+ credentials = attributes.credentials
16
+ credentials["openstack_username"] = hl.ask("Username: ") unless credentials.exists?("openstack_username")
17
+ credentials["openstack_api_key"] = hl.ask("Password: ") unless credentials.exists?("openstack_api_key")
18
+ credentials["openstack_tenant"] = hl.ask("Tenant: ") unless credentials.exists?("openstack_tenant")
19
+ credentials["openstack_auth_url"] = hl.ask("Authorization Token URL: ") unless credentials.exists?("openstack_auth_url")
20
+ end
21
+
22
+ def choose_region
23
+ puts "\n"
24
+ attributes["region"] = hl.ask("OpenStack Region (optional): ")
25
+ end
26
+
27
+ def valid_infrastructure?
28
+ attributes.exists?("region") &&
29
+ attributes.exists?("credentials.openstack_username") &&
30
+ attributes.exists?("credentials.openstack_api_key") &&
31
+ attributes.exists?("credentials.openstack_tenant") &&
32
+ attributes.exists?("credentials.openstack_auth_url")
33
+ end
34
+
35
+ def display_confirmation
36
+ puts "\n"
37
+ if attributes.region.size > 0
38
+ puts "Confirming: Using OpenStack/#{attributes.region}"
39
+ else
40
+ puts "Confirming: Using OpenStack"
41
+ end
42
+ end
43
+ end
44
+
45
+ Cyoi::Cli::Provider.register_provider_cli("openstack", Cyoi::Cli::Providers::ProviderCliOpenStack)
@@ -0,0 +1,3 @@
1
+ module Cyoi
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,75 @@
1
+ describe "cyoi aws" do
2
+ include Cyoi::Cli::Helpers::Settings
3
+ include SettingsHelper
4
+ include Aruba::Api
5
+ before { @settings_dir = File.expand_path("~/.cyoi_client_lib") }
6
+
7
+ it "provider choices already made" do
8
+ setting "provider.name", "aws"
9
+ setting "provider.credentials.aws_access_key_id", "aws_access_key_id"
10
+ setting "provider.credentials.aws_secret_access_key", "aws_secret_access_key"
11
+ setting "provider.region", "us-west-2"
12
+ run_interactive(unescape("cyoi #{settings_dir}"))
13
+ assert_passing_with("Confirming: Using AWS/us-west-2")
14
+ end
15
+
16
+ it "prompts for provider, user chooses aws" do
17
+ run_interactive(unescape("cyoi #{settings_dir}"))
18
+ type("1")
19
+ type("ACCESS")
20
+ type("SECRET")
21
+ type("2")
22
+ type("")
23
+ assert_passing_with(<<-OUT)
24
+ 1. AWS
25
+ 2. OpenStack
26
+ Choose your infrastructure:
27
+ Using provider AWS
28
+
29
+ Access key: Secret key:
30
+ 1. *US East (Northern Virginia) Region (us-east-1)
31
+ 2. US West (Oregon) Region (us-west-2)
32
+ 3. US West (Northern California) Region (us-west-1)
33
+ 4. EU (Ireland) Region (eu-west-1)
34
+ 5. Asia Pacific (Singapore) Region (ap-southeast-1)
35
+ 6. Asia Pacific (Sydney) Region (ap-southeast-2)
36
+ 7. Asia Pacific (Tokyo) Region (ap-northeast-1)
37
+ 8. South America (Sao Paulo) Region (sa-east-1)
38
+ Choose AWS region:
39
+ Confirming: Using AWS/us-west-2
40
+ OUT
41
+ end
42
+
43
+ it "auto-detects aws options in ~/.fog" do
44
+ setup_home_dir
45
+ setup_fog_with_various_accounts_setup
46
+ run_interactive(unescape("cyoi #{settings_dir}"))
47
+ type("3")
48
+ type("6")
49
+ type("")
50
+ assert_passing_with(<<-OUT)
51
+ Auto-detected infrastructure API credentials at ~/.fog (override with $FOG)
52
+ 1. AWS (default)
53
+ 2. OpenStack (default)
54
+ 3. AWS (starkandwayne)
55
+ 4. OpenStack (personal)
56
+ 5. Alternate credentials
57
+ Choose an auto-detected infrastructure:
58
+ Using provider AWS
59
+
60
+
61
+ 1. *US East (Northern Virginia) Region (us-east-1)
62
+ 2. US West (Oregon) Region (us-west-2)
63
+ 3. US West (Northern California) Region (us-west-1)
64
+ 4. EU (Ireland) Region (eu-west-1)
65
+ 5. Asia Pacific (Singapore) Region (ap-southeast-1)
66
+ 6. Asia Pacific (Sydney) Region (ap-southeast-2)
67
+ 7. Asia Pacific (Tokyo) Region (ap-northeast-1)
68
+ 8. South America (Sao Paulo) Region (sa-east-1)
69
+ Choose AWS region:
70
+ Confirming: Using AWS/ap-southeast-2
71
+ OUT
72
+
73
+ settings.provider.region.should == "ap-southeast-2"
74
+ end
75
+ end
@@ -0,0 +1,82 @@
1
+ describe "cyoi openstack" do
2
+ include Cyoi::Cli::Helpers::Settings
3
+ include SettingsHelper
4
+ include Aruba::Api
5
+ before { @settings_dir = File.expand_path("~/.cyoi_client_lib") }
6
+
7
+ it "provider choices already made" do
8
+ setting "provider.name", "openstack"
9
+ setting "provider.credentials.openstack_username", "USERNAME"
10
+ setting "provider.credentials.openstack_api_key", "PASSWORD"
11
+ setting "provider.credentials.openstack_tenant", "TENANT"
12
+ setting "provider.credentials.openstack_auth_url", "TOKENURL"
13
+ setting "provider.region", "us-west"
14
+ run_interactive(unescape("cyoi #{settings_dir}"))
15
+ assert_passing_with("Confirming: Using OpenStack/us-west")
16
+ end
17
+
18
+ it "prompts for everything (no region)" do
19
+ run_interactive(unescape("cyoi #{settings_dir}"))
20
+ type("2")
21
+ type("USERNAME")
22
+ type("PASSWORD")
23
+ type("TENANT")
24
+ type("TOKENURL")
25
+ type("")
26
+ type("")
27
+ assert_passing_with(<<-OUT)
28
+ 1. AWS
29
+ 2. OpenStack
30
+ Choose your infrastructure:
31
+ Using provider OpenStack
32
+
33
+ Username: Password: Tenant: Authorization Token URL:
34
+ OpenStack Region (optional):
35
+ Confirming: Using OpenStack
36
+ OUT
37
+ end
38
+
39
+ it "prompts for everything (with region)" do
40
+ run_interactive(unescape("cyoi #{settings_dir}"))
41
+ type("2")
42
+ type("USERNAME")
43
+ type("PASSWORD")
44
+ type("TENANT")
45
+ type("TOKENURL")
46
+ type("REGION")
47
+ type("")
48
+ assert_passing_with(<<-OUT)
49
+ 1. AWS
50
+ 2. OpenStack
51
+ Choose your infrastructure:
52
+ Using provider OpenStack
53
+
54
+ Username: Password: Tenant: Authorization Token URL:
55
+ OpenStack Region (optional):
56
+ Confirming: Using OpenStack/REGION
57
+ OUT
58
+ end
59
+
60
+ it "auto-detects several openstack options in ~/.fog" do
61
+ setup_home_dir
62
+ setup_fog_with_various_accounts_setup
63
+ run_interactive(unescape("cyoi #{settings_dir}"))
64
+ type("4")
65
+ type("REGION")
66
+ type("")
67
+ assert_passing_with(<<-OUT)
68
+ Auto-detected infrastructure API credentials at ~/.fog (override with $FOG)
69
+ 1. AWS (default)
70
+ 2. OpenStack (default)
71
+ 3. AWS (starkandwayne)
72
+ 4. OpenStack (personal)
73
+ 5. Alternate credentials
74
+ Choose an auto-detected infrastructure:
75
+ Using provider OpenStack
76
+
77
+
78
+ OpenStack Region (optional):
79
+ Confirming: Using OpenStack/REGION
80
+ OUT
81
+ end
82
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup(:default, :test)
8
+
9
+ $:.unshift(File.expand_path("../../lib", __FILE__))
10
+
11
+ require "rspec/core"
12
+ require "cyoi"
13
+ require "cyoi/cli/provider"
14
+
15
+ require "aruba/api"
16
+
17
+ # The following is commented out because it causes
18
+ # the following error:
19
+ # EOFError:
20
+ # The input stream is exhausted.
21
+ #
22
+ # require 'aruba/in_process'
23
+ # Aruba::InProcess.main_class = Cyoi::Cli::Provider
24
+ # Aruba.process = Aruba::InProcess
25
+
26
+ # for the #sh helper
27
+ require "rake"
28
+ require "rake/file_utils"
29
+
30
+ # load all files in spec/support/* (but not lower down)
31
+ Dir[File.dirname(__FILE__) + '/support/*'].each do |path|
32
+ require path unless File.directory?(path)
33
+ end
34
+
35
+ def setup_fog_with_various_accounts_setup
36
+ File.open(File.expand_path("~/.fog"), "w") do |f|
37
+ f << {
38
+ default: {
39
+ aws_access_key_id: "PERSONAL_ACCESS_KEY",
40
+ aws_secret_access_key: "PERSONAL_SECRET",
41
+ openstack_username: "USERNAME",
42
+ openstack_api_key: "PASSWORD",
43
+ openstack_tenant: "TENANT",
44
+ openstack_auth_url: "URL"
45
+ },
46
+ starkandwayne: {
47
+ aws_access_key_id: "PERSONAL_ACCESS_KEY",
48
+ aws_secret_access_key: "PERSONAL_SECRET",
49
+ },
50
+ personal: {
51
+ openstack_username: "USERNAME",
52
+ openstack_api_key: "PASSWORD",
53
+ openstack_tenant: "TENANT",
54
+ openstack_auth_url: "URL"
55
+ }
56
+ }.to_yaml
57
+ end
58
+ end
59
+
60
+ def spec_asset(filename)
61
+ File.expand_path("../assets/#{filename}", __FILE__)
62
+ end
63
+
64
+ def setup_home_dir
65
+ home_dir = File.expand_path("../../tmp/home", __FILE__)
66
+ FileUtils.rm_rf(home_dir)
67
+ FileUtils.mkdir_p(home_dir)
68
+ ENV['HOME'] = home_dir
69
+ end
70
+
71
+ def setup_path
72
+ ENV['PATH'] = File.expand_path("../../bin", __FILE__) + ":" + ENV['PATH']
73
+ end
74
+ # returns the file path to a file
75
+ # in the fake $HOME folder
76
+ def home_file(*path)
77
+ File.join(ENV['HOME'], *path)
78
+ end
79
+
80
+ RSpec.configure do |c|
81
+ c.before do
82
+ setup_home_dir
83
+ setup_path
84
+ end
85
+
86
+ c.color_enabled = true
87
+ end
@@ -0,0 +1,9 @@
1
+ # assumes @cmd is Inception::Cli instance
2
+ module SettingsHelper
3
+ # Set a nested setting with "key1.key2.key3" notation
4
+ def setting(nested_key, value)
5
+ settings.set(nested_key, value)
6
+ save_settings!
7
+ end
8
+
9
+ end
@@ -0,0 +1,18 @@
1
+ module StdoutCapture
2
+ # Captures stdout within the block
3
+ # Usage:
4
+ #
5
+ # out = capture_stdout do
6
+ # puts "this will not be shown"
7
+ # end
8
+ # out.should == "this will not be shown"
9
+ def capture_stdout(&block)
10
+ out = StringIO.new
11
+ $stdout = out
12
+ yield
13
+ out.rewind
14
+ return out.read
15
+ ensure
16
+ $stdout = STDOUT
17
+ end
18
+ end
File without changes
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cyoi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dr Nic Williams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: highline
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.6'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
30
+ - !ruby/object:Gem::Dependency
31
+ name: settingslogic
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.0.9
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.0.9
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: aruba
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: A library to ask an end-user to choose an infrastructure (AWS, OpenStack,
111
+ etc), region, and login credentials.
112
+ email:
113
+ - drnicwilliams@gmail.com
114
+ executables:
115
+ - cyoi
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .rspec
121
+ - .travis.yml
122
+ - Gemfile
123
+ - Guardfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - bin/cyoi
128
+ - cyoi.gemspec
129
+ - lib/cyoi.rb
130
+ - lib/cyoi/cli.rb
131
+ - lib/cyoi/cli/auto_detection.rb
132
+ - lib/cyoi/cli/auto_detection/auto_detection_fog.rb
133
+ - lib/cyoi/cli/helpers.rb
134
+ - lib/cyoi/cli/helpers/interactions.rb
135
+ - lib/cyoi/cli/helpers/settings.rb
136
+ - lib/cyoi/cli/provider.rb
137
+ - lib/cyoi/cli/providers/provider_cli.rb
138
+ - lib/cyoi/cli/providers/provider_cli_aws.rb
139
+ - lib/cyoi/cli/providers/provider_cli_openstack.rb
140
+ - lib/cyoi/version.rb
141
+ - spec/.DS_Store
142
+ - spec/integration/cli/provider_aws_spec.rb
143
+ - spec/integration/cli/provider_openstack_spec.rb
144
+ - spec/spec_helper.rb
145
+ - spec/support/settings_helper.rb
146
+ - spec/support/stdout_capture.rb
147
+ - spec/unit/.gitkeep
148
+ homepage: https://github.com/drnic/cyoi
149
+ licenses:
150
+ - MIT
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ segments:
162
+ - 0
163
+ hash: -525265882681601916
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ! '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ segments:
171
+ - 0
172
+ hash: -525265882681601916
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 1.8.25
176
+ signing_key:
177
+ specification_version: 3
178
+ summary: A library to ask an end-user to choose an infrastructure (AWS, OpenStack,
179
+ etc), region, and login credentials. This library was extracted from [inception-server](https://github.com/drnic/inception-server)
180
+ for reuse by [bosh-bootstrap](https://github.com/StarkAndWayne/bosh-bootstrap).
181
+ It might also be useful to your own CLI applications that need to ask a user to
182
+ give you their infrastructure credentials/region so your application can control
183
+ their infrastructure (say via [fog](http://fog.io)).
184
+ test_files:
185
+ - spec/.DS_Store
186
+ - spec/integration/cli/provider_aws_spec.rb
187
+ - spec/integration/cli/provider_openstack_spec.rb
188
+ - spec/spec_helper.rb
189
+ - spec/support/settings_helper.rb
190
+ - spec/support/stdout_capture.rb
191
+ - spec/unit/.gitkeep