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.
- checksums.yaml +15 -0
- data/.gitignore +14 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +675 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/undercloud-install-instack-virt.rb +14 -0
- data/bin/undercloud-install-satellite.rb +20 -0
- data/bin/undercloud-install-vanilla-rhel.rb +18 -0
- data/egon.gemspec +29 -0
- data/lib/egon/overcloud/undercloud_handle/deployment.rb +46 -0
- data/lib/egon/overcloud/undercloud_handle/deployment_role.rb +9 -0
- data/lib/egon/overcloud/undercloud_handle/flavor.rb +67 -0
- data/lib/egon/overcloud/undercloud_handle/image.rb +20 -0
- data/lib/egon/overcloud/undercloud_handle/node.rb +109 -0
- data/lib/egon/overcloud/undercloud_handle.rb +41 -0
- data/lib/egon/undercloud/commands.rb +44 -0
- data/lib/egon/undercloud/installer.rb +43 -0
- data/lib/egon/undercloud/ssh-connection.rb +83 -0
- data/lib/egon/version.rb +3 -0
- data/lib/egon.rb +5 -0
- data/rubygem-egon.spec +112 -0
- data/test/test_ssh_connection.rb +13 -0
- data/test/test_undercloud.rb +45 -0
- metadata +143 -0
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,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,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
|
+
|
data/lib/egon/version.rb
ADDED