cyoi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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