egon 0.0.1

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.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Egon
2
+
3
+ Ruby gem for interacting with TripleO
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'egon'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install egon
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/egon/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,14 @@
1
+ require 'egon/undercloud/commands'
2
+ require 'egon/undercloud/ssh-connection'
3
+ require 'egon/undercloud/installer'
4
+
5
+ SSH_HOST = ARGV[0]
6
+ SSH_USER = ARGV[1]
7
+ SSH_PASSWORD = ARGV[2]
8
+
9
+ connection = Egon::Undercloud::SSHConnection.new(SSH_HOST, SSH_USER, SSH_PASSWORD)
10
+ installer = Egon::Undercloud::Installer.new(connection)
11
+ installer.install(Egon::Undercloud::Commands.OSP7_instack_virt)
12
+ while !installer.completed?
13
+ sleep 1
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'egon/undercloud/commands'
2
+ require 'egon/undercloud/ssh-connection'
3
+ require 'egon/undercloud/installer'
4
+
5
+ SSH_HOST = ARGV[0]
6
+ SSH_USER = ARGV[1]
7
+ SSH_PASSWORD = ARGV[2]
8
+
9
+ # Satellite URL
10
+ # https://server
11
+ SATELLITE_URL = ARGV[3]
12
+ SATELLITE_ORG = ARGV[4]
13
+ SATELLITE_ACTIVATION_KEY = ARGV[5]
14
+
15
+ connection = Egon::Undercloud::SSHConnection.new(SSH_HOST, SSH_USER, SSH_PASSWORD)
16
+ installer = Egon::Undercloud::Installer.new(connection)
17
+ installer.install(Egon::Undercloud::Commands.OSP7_satellite(SATELLITE_URL, SATELLITE_ORG, SATELLITE_ACTIVATION_KEY))
18
+ while !installer.completed?
19
+ sleep 1
20
+ end
@@ -0,0 +1,18 @@
1
+ require 'egon/undercloud/commands'
2
+ require 'egon/undercloud/ssh-connection'
3
+ require 'egon/undercloud/installer'
4
+
5
+ SSH_HOST = ARGV[0]
6
+ SSH_USER = ARGV[1]
7
+ SSH_PASSWORD = ARGV[2]
8
+
9
+ RHSM_USER = ARGV[3]
10
+ RHSM_PASSWORD = ARGV[4]
11
+ RHSM_POOL_ID = ARGV[5]
12
+
13
+ connection = Egon::Undercloud::SSHConnection.new(SSH_HOST, SSH_USER, SSH_PASSWORD)
14
+ installer = Egon::Undercloud::Installer.new(connection)
15
+ installer.install(Egon::Undercloud::Commands.OSP7_vanilla_rhel(RHSM_USER, RHSM_PASSWORD, RHSM_POOL_ID))
16
+ while !installer.completed?
17
+ sleep 1
18
+ end
data/egon.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/egon/version', __FILE__)
3
+ require 'date'
4
+
5
+ lib = File.expand_path('../lib', __FILE__)
6
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = "egon"
10
+ s.version = Egon::VERSION
11
+ s.authors = ['Egon and Fusor team']
12
+ s.email = ['foreman-dev+egon@googlegroups.com']
13
+ s.summary = %q{A library on top of Fog that encapsulates TripleO deployment operations}
14
+ s.description = %q{}
15
+ s.homepage = 'https://github.com/fusor/egon'
16
+ s.date = Date.today.to_s
17
+ s.license = 'GPL-3.0+'
18
+
19
+ s.files = `git ls-files -z`.split("\x0")
20
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ s.test_files = s.files.grep(%r{^(test|s|features)/})
22
+ s.require_paths = ["lib"]
23
+
24
+ s.add_development_dependency "bundler", "~> 1.7"
25
+ s.add_development_dependency "rake", "~> 10.0"
26
+ s.add_development_dependency "fog", "~> 1.29.0"
27
+ s.add_development_dependency "net-ssh", "~> 2.9.2"
28
+ s.add_development_dependency "rspec", "~> 3.2.0"
29
+ end
@@ -0,0 +1,46 @@
1
+ module Overcloud
2
+ module Deployment
3
+
4
+ def get_plan(plan_name)
5
+ service('Planning').plans.find_by_name(plan_name)
6
+ end
7
+
8
+ def edit_plan_parameters(plan_name, parameters)
9
+ get_plan(plan_name).patch(:parameters => parameters)
10
+ end
11
+
12
+ def edit_plan_deployment_role_count(plan_name, role_name, count)
13
+ parameter = {"name" => role_name + "-1::count", "value" => count.to_s}
14
+ edit_plan_parameters(plan_name, [parameter])
15
+ end
16
+
17
+ def edit_plan_deployment_role_image(plan_name, role_name, image_uuid)
18
+ parameter = {"name" => role_name + "-1::Image", "value" => image_uuid}
19
+ edit_plan_parameters([parameter])
20
+ end
21
+
22
+ def edit_plan_deployment_role_flavor(plan_name, role_name, flavor_name)
23
+ parameter = {"name" => role_name + "-1::Flavor", "value" => flavor_name}
24
+ edit_plan_parameters(plan_name, [parameter])
25
+ end
26
+
27
+ def deploy_plan(plan_name)
28
+ plan = get_plan(plan_name)
29
+ stack_parameters = {
30
+ :stack_name => plan.name,
31
+ :template => plan.master_template,
32
+ :environment => plan.environment,
33
+ :files => plan.provider_resource_templates,
34
+ :password => @password,
35
+ :timeout_mins => 60,
36
+ :disable_rollback => true
37
+ }
38
+ service('Orchestration').stacks.new.save(stack_parameters)
39
+ end
40
+
41
+ def get_stack(stack_name)
42
+ service('Orchestration').stacks.get(stack_name)
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ module Overcloud
2
+ module DeploymentRole
3
+
4
+ def list_deployment_roles
5
+ service('Planning').roles
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,67 @@
1
+ require_relative 'image'
2
+
3
+ module Overcloud
4
+ module Flavor
5
+
6
+ def list_flavors
7
+ service('Compute').flavors.all
8
+ end
9
+
10
+ def get_flavor(flavor_id)
11
+ service('Compute').flavors.get(flavor_id)
12
+ end
13
+
14
+ def create_flavor(flavor_parameters)
15
+ flavor = service('Compute').flavors.create(flavor_parameters)
16
+ if flavor_parameters.key?(:extra_specs)
17
+ create_flavor_extra_specs(flavor.id, flavor_parameters[:extra_specs])
18
+ end
19
+ end
20
+
21
+ def get_flavor_extra_specs(flavor_id)
22
+ get_flavor(flavor_id).metadata
23
+ end
24
+
25
+ def create_flavor_extra_specs(flavor_id, extra_specs)
26
+ get_flavor(flavor_id).create_metadata(extra_specs)
27
+ end
28
+
29
+ def create_flavor_from_node(node)
30
+ cpus = node.properties['cpus']
31
+ memory_mb = node.properties['memory_mb']
32
+ local_gb = node.properties['local_gb']
33
+ cpu_arch = node.properties['cpu_arch']
34
+
35
+ flavor_parameters = {
36
+ :name => 'Flavor-' + cpus + '-' + cpu_arch + '-' + memory_mb + '-' + local_gb,
37
+ :ram => memory_mb,
38
+ :vcpus => cpus,
39
+ :disk => local_gb,
40
+ :is_public => true,
41
+ :extra_specs => {
42
+ :cpu_arch => cpu_arch,
43
+ :'capabilities:boot_option' => 'local',
44
+ :'baremetal:deploy_kernel_id' => get_baremetal_deploy_kernel_image.id,
45
+ :'baremetal:deploy_ramdisk_id' => get_baremetal_deploy_ramdisk_image.id
46
+ }
47
+ }
48
+
49
+ if !flavor_exists?(flavor_parameters)
50
+ create_flavor(flavor_parameters)
51
+ end
52
+ end
53
+
54
+ def flavor_exists?(flavor_parameters)
55
+ for flavor in list_flavors
56
+ if flavor.ram == flavor_parameters[:ram].to_i &&
57
+ flavor.vcpus == flavor_parameters[:vcpus].to_i &&
58
+ flavor.disk == flavor_parameters[:disk].to_i &&
59
+ flavor.metadata['cpu_arch'] == flavor_parameters[:extra_specs][:cpu_arch]
60
+ return true
61
+ end
62
+ end
63
+ false
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ module Overcloud
2
+ module Image
3
+
4
+ def list_images
5
+ service('Image').images
6
+ end
7
+
8
+ def find_image_by_name(image_name)
9
+ service('Image').images.find{|image| image.name == image_name}
10
+ end
11
+
12
+ def get_baremetal_deploy_kernel_image
13
+ find_image_by_name('bm-deploy-kernel')
14
+ end
15
+
16
+ def get_baremetal_deploy_ramdisk_image
17
+ find_image_by_name('bm-deploy-ramdisk')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,109 @@
1
+ require_relative 'flavor'
2
+ require 'csv'
3
+ require 'timeout'
4
+
5
+ module Overcloud
6
+ module Node
7
+
8
+ def list_nodes
9
+ service('Baremetal').nodes.details
10
+ end
11
+
12
+ def create_node(node_parameters, create_flavor = false)
13
+ node = service('Baremetal').nodes.create(node_parameters)
14
+ create_port({:node_uuid => node.uuid, :address => node_parameters[:address]})
15
+
16
+ create_flavor_from_node(node) if create_flavor
17
+
18
+ node.set_provision_state('manage')
19
+ introspect_node(node)
20
+ Thread.new {
21
+ timeout(900) {
22
+ while not introspect_node_status(node) do
23
+ sleep(15)
24
+ end
25
+ node.set_provision_state('provide')
26
+ }
27
+ }
28
+ node
29
+ end
30
+
31
+ def create_port(port_parameters)
32
+ service('Baremetal').ports.create(port_parameters)
33
+ end
34
+
35
+ def create_nodes_from_csv(csv_file, create_flavor = false)
36
+ CSV.foreach(csv_file) do |node_data|
37
+ memory_mb = node_data[0]
38
+ local_gb = node_data[1]
39
+ cpus = node_data[2]
40
+ cpu_arch = node_data[3]
41
+ driver = node_data[4]
42
+ mac_address = node_data[8]
43
+ if driver == 'pxe_ssh'
44
+ driver_info = {
45
+ :ssh_address => node_data[5],
46
+ :ssh_username => node_data[6],
47
+ :ssh_key_contents => node_data[7],
48
+ :ssh_virt_type => 'virsh',
49
+ :deploy_kernel => get_baremetal_deploy_kernel_image.id,
50
+ :deploy_ramdisk => get_baremetal_deploy_ramdisk_image.id
51
+ }
52
+ elsif driver == 'pxe_ipmitool'
53
+ driver_info = {
54
+ :ipmi_address => node_data[5],
55
+ :ipmi_username => node_data[6],
56
+ :ipmi_password => node_data[7],
57
+ :pxe_deploy_kernel => get_baremetal_deploy_kernel_image.id,
58
+ :pxe_deploy_ramdisk => get_baremetal_deploy_ramdisk_image.id
59
+ }
60
+ else
61
+ raise "Unknown node driver: #{driver}"
62
+ end
63
+
64
+ node_parameters = {
65
+ :driver => driver,
66
+ :driver_info => driver_info,
67
+ :properties => {
68
+ :cpus => cpus,
69
+ :memory_mb => memory_mb,
70
+ :local_gb => local_gb,
71
+ :cpu_arch => cpu_arch,
72
+ :capabilities => 'boot_option:local'
73
+ },
74
+ :address => mac_address
75
+ }
76
+ node = create_node(node_parameters, create_flavor)
77
+ end
78
+ end
79
+
80
+ ## THESE METHODS ARE TEMPORARY UNTIL IRONIC-DISCOVERD IS ADDED TO
81
+ ## OPENSTACK AND KEYSTONE
82
+
83
+ def introspect_node(node)
84
+ uri = "http://#{@auth_url}:5050/v1/introspection/#{node.uuid}"
85
+ auth_token = service('Baremetal').instance_variable_get(:@auth_token)
86
+ response = Fog::Core::Connection.new(uri, false).request({
87
+ :expects => 202,
88
+ :headers => {'Content-Type' => 'application/json',
89
+ 'Accept' => 'application/json',
90
+ 'X-Auth-Token' => auth_token},
91
+ :method => 'POST'
92
+ })
93
+ end
94
+
95
+ def introspect_node_status(node)
96
+ uri = "http://#{@auth_url}:5050/v1/introspection/#{node.uuid}"
97
+ auth_token = service('Baremetal').instance_variable_get(:@auth_token)
98
+ response = Fog::Core::Connection.new(uri, false).request({
99
+ :expects => 200,
100
+ :headers => {'Content-Type' => 'application/json',
101
+ 'Accept' => 'application/json',
102
+ 'X-Auth-Token' => auth_token},
103
+ :method => 'GET'
104
+ })
105
+ Fog::JSON.decode(response.body)['finished']
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,41 @@
1
+ require 'fog'
2
+ require_relative 'undercloud_handle/deployment'
3
+ require_relative 'undercloud_handle/deployment_role'
4
+ require_relative 'undercloud_handle/flavor'
5
+ require_relative 'undercloud_handle/image'
6
+ require_relative 'undercloud_handle/node'
7
+
8
+ module Overcloud
9
+ class UndercloudHandle
10
+
11
+ include Overcloud::Deployment
12
+ include Overcloud::DeploymentRole
13
+ include Overcloud::Flavor
14
+ include Overcloud::Image
15
+ include Overcloud::Node
16
+
17
+ def initialize(username, password, auth_url, port = 5000)
18
+ @username = username
19
+ @password = password
20
+ @auth_url = auth_url
21
+ @port = port
22
+ end
23
+
24
+ private
25
+
26
+ def service(service_name)
27
+ fog_parameters = {
28
+ :provider => 'OpenStack',
29
+ :openstack_auth_url => 'http://' + @auth_url + ':' + @port.to_s + '/v2.0/tokens',
30
+ :openstack_username => @username,
31
+ :openstack_api_key => @password,
32
+ }
33
+
34
+ if service_name == 'Planning'
35
+ return Fog::Openstack.const_get(service_name).new(fog_parameters)
36
+ end
37
+ return Fog.const_get(service_name).new(fog_parameters)
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+
2
+ module Egon
3
+ module Undercloud
4
+ class Commands
5
+
6
+ def self.OSP7_satellite(satellite_url, org, activation_key)
7
+ return "
8
+ curl -k -O #{satellite_url}/pub/katello-ca-consumer-latest.noarch.rpm
9
+ sudo yum install -y katello-ca-consumer-latest.noarch.rpm
10
+ sudo subscription-manager register --org=\"#{org}\" --activationkey=\"#{activation_key}\"
11
+ sudo yum clean all
12
+ #{OSP7_COMMON}"
13
+ end
14
+
15
+ def self.OSP7_vanilla_rhel(rhsm_user, rhsm_password, rhsm_pool_id)
16
+ return "
17
+ sudo subscription-manager register --force --username=\"#{rhsm_user}\" --password=\"#{rhsm_password}\"
18
+ sudo subscription-manager attach --pool=\"#{rhsm_pool_id}\"
19
+ sudo subscription-manager repos --enable=rhel-7-server-rpms \
20
+ --enable=rhel-7-server-optional-rpms --enable=rhel-7-server-extras-rpms \
21
+ --enable=rhel-7-server-openstack-6.0-rpms
22
+ #{OSP7_COMMON}"
23
+ end
24
+
25
+ def self.OSP7_instack_virt
26
+ return OSP7_COMMON
27
+ end
28
+
29
+ OSP7_COMMON = "
30
+ sudo yum install -y http://mirrors.einstein.yu.edu/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
31
+ sudo yum install -y https://rdoproject.org/repos/openstack-kilo/rdo-release-kilo.rpm
32
+ sudo curl -o /etc/yum.repos.d/rdo-management-trunk.repo http://trunk-mgt.rdoproject.org/centos-kilo/current-passed-ci/delorean-rdo-management.repo
33
+ sudo yum install -y python-rdomanager-oscplugin
34
+ # TODO: answers file should come from RHCI
35
+ cp -f /usr/share/instack-undercloud/undercloud.conf.sample ~/undercloud.conf;
36
+ # TODO: for baremetal a nodes.csv file may also be required
37
+ openstack undercloud install
38
+ sudo cp /root/tripleo-undercloud-passwords .
39
+ sudo chown $USER: tripleo-undercloud-passwords
40
+ sudo cp /root/stackrc .
41
+ sudo chown $USER: stackrc"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ module Egon
2
+ module Undercloud
3
+ class Installer
4
+ attr_reader :started
5
+ alias_method :started?, :started
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+ @completed = false
10
+ @started = false
11
+ @failure = false
12
+ end
13
+
14
+ def completed?
15
+ @completed
16
+ end
17
+
18
+ def set_completed(bool)
19
+ @completed = bool
20
+ end
21
+
22
+ def failure?
23
+ @failure
24
+ end
25
+
26
+ def set_failure(bool)
27
+ @failure = bool
28
+ end
29
+
30
+ def install(commands)
31
+ @started = true
32
+ @completed = false
33
+
34
+ @connection.on_complete(lambda { set_completed(true) })
35
+ @connection.on_failure(lambda { set_failure(true) })
36
+
37
+ Thread.new {
38
+ @connection.execute(commands)
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,83 @@
1
+ require 'net/ssh'
2
+ require 'stringio'
3
+
4
+ # TODO: Remove this class when this branch is merged,
5
+ # https://github.com/fusor/fusor/blob/deploy-cfme/server/app/lib/utils/fusor/command_utils.rb,
6
+ # and additional changes here have been applied.
7
+ module Egon
8
+ module Undercloud
9
+ class SSHConnection
10
+ def initialize(host, user, password)
11
+ @host = host
12
+ @user = user
13
+ @password = password
14
+ end
15
+
16
+ def call_complete
17
+ @on_complete.call if @on_complete
18
+ end
19
+
20
+ def on_complete(hook)
21
+ @on_complete = hook
22
+ end
23
+
24
+ def call_failure
25
+ @on_failure.call if @on_failure
26
+ end
27
+
28
+ def on_failure(hook)
29
+ @on_failure = hook
30
+ end
31
+
32
+ def execute(commands, stringio = nil)
33
+ begin
34
+ # :timeout => how long to wait for the initial connection to be made
35
+ Net::SSH.start(@host, @user, :password => @password, :timeout => 2,
36
+ :auth_methods => ["password"],
37
+ :number_of_password_prompts => 0) do |ssh|
38
+ # open a new channel and configure a minimal set of callbacks, then run
39
+ # the event loop until the channel finishes (closes)
40
+ channel = ssh.open_channel do |ch|
41
+ ch.request_pty do |ch, success|
42
+ if !success
43
+ puts "Error: could not obtain pty"
44
+ call_failure
45
+ call_complete
46
+ end
47
+ end
48
+ ch.exec commands do |ch, success|
49
+ call_failure unless success
50
+
51
+ # "on_data" is called when the process writes something to stdout
52
+ ch.on_data do |c, data|
53
+ $stdout.print data if stringio.nil?
54
+ stringio.puts data unless stringio.nil?
55
+ end
56
+
57
+ # "on_extended_data" is called when the process writes something to stderr
58
+ ch.on_extended_data do |c, type, data|
59
+ $stderr.print data if stringio.nil?
60
+ stringio.puts data unless stringio.nil?
61
+ call_failure
62
+ end
63
+
64
+ ch.on_close { call_complete }
65
+ end
66
+ end
67
+
68
+ channel.wait
69
+ end
70
+ call_complete
71
+ rescue Exception => e
72
+ puts e.message
73
+ puts e.backtrace.inspect
74
+ call_failure
75
+ call_complete
76
+ stringio.puts e.message unless stringio.nil?
77
+ e.message if stringio.nil?
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,3 @@
1
+ module Egon
2
+ VERSION = "0.0.1"
3
+ end
data/lib/egon.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "egon/version"
2
+
3
+ module Egon
4
+ # Your code goes here...
5
+ end