knife-lpar 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "knife-lpar/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "knife-lpar"
8
+ spec.version = Knife::Lpar::VERSION
9
+ spec.authors = ["Scott Hain"]
10
+ spec.email = ["shain@chef.io"]
11
+ spec.summary = %q{LPAR creation}
12
+ spec.description = spec.summary
13
+ spec.homepage = "http://github.com/chef/knife-lpar"
14
+ spec.license = "Apache 2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "net-ssh", "~> 2.6"
22
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014-2016 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "io/console"
19
+ require "net/ssh"
20
+
21
+ class Chef
22
+ class Knife
23
+ module LparBase
24
+
25
+ # I hate this name but I'm not thinking of anything better right now.
26
+ def print_with_output(message, output = nil)
27
+ if output.nil? || output.empty?
28
+ ui.info message
29
+ else
30
+ ui.info message + " - " + output
31
+ end
32
+ end
33
+
34
+ def run_remote_command(ssh, command)
35
+ return_val = nil
36
+ ssh.exec! command do |ch, stream, data|
37
+ if stream == :stdout
38
+ return_val = data.chomp
39
+ else
40
+ # some exception is in order I think
41
+ ui.error "Something went wrong:"
42
+ ui.error data.to_s
43
+ exit 1
44
+ end
45
+ end
46
+ return_val
47
+ end
48
+
49
+ # quick and dirty password prompt, because I'm cool like that
50
+ def get_password
51
+ print "Enter root password for HMC: "
52
+ STDIN.noecho(&:gets).chomp
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,247 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014-2016 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "chef/knife"
19
+ require "chef/knife/lpar_base"
20
+
21
+ class Chef
22
+ class Knife
23
+ class LparCreate < Knife
24
+ include Chef::Knife::LparBase
25
+
26
+ banner "knife lpar create HMC [options]"
27
+
28
+ option :name,
29
+ :short => "-n NAME",
30
+ :long => "--name",
31
+ :description => "LPAR Name"
32
+
33
+ option :profile,
34
+ :short => "-p PROFILE",
35
+ :long => "--profile",
36
+ :description => "LPAR Profile Name"
37
+
38
+ option :virtual_server,
39
+ :short => "-v SERVER",
40
+ :long => "--virtual-server",
41
+ :description => "Virtual Server Name"
42
+
43
+ option :vios,
44
+ :long => "--vios NAME",
45
+ :description => "Virtual I/O Server LPAR Name"
46
+
47
+ option :min_mem,
48
+ :long => "--min-mem MEM",
49
+ :description => "Minimum Memory in mb (default 1024)",
50
+ :default => 1024
51
+
52
+ option :desired_mem,
53
+ :long => "--desired-mem MEM",
54
+ :description => "Desired Memory in mb (default 4096)",
55
+ :default => 4096
56
+
57
+ option :max_mem,
58
+ :long => "--max-mem MEM",
59
+ :description => "Max Memory in mb (default 16384)",
60
+ :default => 16384
61
+
62
+ option :min_procs,
63
+ :long => "--min-procs PROCS",
64
+ :description => "Minimum number of Processors (default 1)",
65
+ :default => 1
66
+
67
+ option :desired_procs,
68
+ :long => "--desired-procs PROCS",
69
+ :description => "Desired number of Processors (default 2)",
70
+ :default => 2
71
+
72
+ option :max_procs,
73
+ :long => "--max-procs PROCS",
74
+ :description => "Max number of Processors (default 4)",
75
+ :default => 4
76
+
77
+ option :min_proc_units,
78
+ :long => "--min-proc_units UNITS",
79
+ :description => "Minimum number of processor units (default 1)",
80
+ :default => 1
81
+
82
+ option :desired_proc_units,
83
+ :long => "--desired-proc_units UNITS",
84
+ :description => "Desired number of processor units (default 2)",
85
+ :default => 2
86
+
87
+ option :max_proc_units,
88
+ :long => "--max-proc_units UNITS",
89
+ :description => "Max number of processor units (default 4)",
90
+ :default => 4
91
+
92
+ option :help,
93
+ :long => "--help",
94
+ :description => "Prints this menu"
95
+
96
+ option :disk_name,
97
+ :long => "--disk-name DISK",
98
+ :description => "Disk image name (e.g. AIX_6_1_vol1)"
99
+
100
+ #
101
+ # Run the plugin
102
+ #
103
+ def run
104
+ read_and_validate_params
105
+ @password = get_password
106
+ create_lpar
107
+ end
108
+
109
+ #
110
+ # Reads the input parameters and validates them.
111
+ # Will exit if it encounters an error
112
+ #
113
+ def read_and_validate_params
114
+ if @name_args.length < 1
115
+ show_usage
116
+ exit 1
117
+ end
118
+
119
+ if config[:name].nil? ||
120
+ config[:vios].nil? ||
121
+ config[:virtual_server].nil? ||
122
+ config[:disk_name].nil?
123
+ show_usage
124
+ exit 1
125
+ end
126
+
127
+ if config[:profile].nil?
128
+ config[:profile] = config[:name]
129
+ end
130
+ end
131
+
132
+ def create_lpar
133
+ Net::SSH.start(@name_args[0], "hscroot", :password => @password) do |ssh|
134
+ # some background checks
135
+ # check for existing lpar with name
136
+ ui.info "Searching for existing lpar with name: #{config[:name]}"
137
+ command = "lssyscfg -m #{config[:virtual_server]} -F name -r lpar | grep #{config[:name]}"
138
+ output = run_remote_command(ssh, command)
139
+ unless output.nil?
140
+ ui.fatal "An lpar already exists with the name #{config[:name]}"
141
+ exit 1
142
+ end
143
+ ui.info "lpar not found, creation imminent"
144
+
145
+ # find the last vscsi device number
146
+ ui.info "Looking for next device number in sequence"
147
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"lsdev -type disk -virtual -field name\" | tail -1"
148
+ last_vscsi = run_remote_command(ssh, command)
149
+ ui.info "Found existing device - #{last_vscsi}"
150
+
151
+ # use the vscsi number to find the actual physical ID so we can find which vios slot it's in
152
+ ui.info "Finding vios mapping for device - #{last_vscsi}"
153
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"lsdev -dev #{last_vscsi} -field physloc -fmt \\\":\\\"\""
154
+ last_vscsi_phy_loc = run_remote_command(ssh, command)
155
+ prev_loc = last_vscsi_phy_loc.match('.*-C(\d+)-.*')[1]
156
+ ui.info "Found vios mapping #{prev_loc}"
157
+ new_virt_loc = prev_loc.to_i + 1
158
+ ui.info "Will use new mapping #{new_virt_loc}"
159
+
160
+ # create the new lpar
161
+ ui.info "Creating new lpar #{config[:name]}"
162
+ command = "mksyscfg -m #{config[:virtual_server]} -r lpar \
163
+ -i \"name=#{config[:name]}, \
164
+ profile_name=#{config[:profile]}, \
165
+ lpar_env=aixlinux, \
166
+ min_mem=#{config[:min_mem]}, \
167
+ desired_mem=#{config[:desired_mem]}, \
168
+ max_mem=#{config[:max_mem]}, \
169
+ proc_mode=shared, \
170
+ min_procs=#{config[:min_procs]}, \
171
+ desired_procs=#{config[:desired_procs]}, \
172
+ max_procs=#{config[:max_procs]}, \
173
+ min_proc_units=#{config[:min_proc_units]}, \
174
+ desired_proc_units=#{config[:desired_proc_units]}, \
175
+ max_proc_units=#{config[:max_proc_units]}, \
176
+ sharing_mode=uncap, uncap_weight=128, \
177
+ boot_mode=norm, max_virtual_slots=10, \
178
+ \\\"virtual_eth_adapters=3/0/1//0/0\\\", \
179
+ \\\"virtual_scsi_adapters=2/client//#{config[:vios]}/#{new_virt_loc}/1\\\"\""
180
+ output = run_remote_command(ssh, command)
181
+ ui.info "Creation Successful"
182
+
183
+ # now we have to figure out what LPAR we just created
184
+ ui.info "Finding vhost name"
185
+ command = "lssyscfg -m #{config[:virtual_server]} --filter \"lpar_names=#{config[:name]}\" -F lpar_id -r lpar"
186
+ output = run_remote_command(ssh, command)
187
+ # and of course it doesn't match, 0 based vs 1 based counting
188
+ vhost = output.to_i - 1
189
+ vhost_name = "vhost#{vhost}"
190
+ ui.info "#{config[:name]} is #{vhost_name}"
191
+
192
+ # Add the virtual io server vscsi mapping
193
+ ui.info "Mapping #{new_virt_loc} between #{config[:vios]} and #{config[:name]}"
194
+ command = "chhwres -r virtualio -m #{config[:virtual_server]} -o a -p #{config[:vios]} --rsubtype scsi -s #{new_virt_loc} -a \"adapter_type=server, remote_lpar_name=#{config[:name]}, remote_slot_num=2\""
195
+ output = run_remote_command(ssh, command)
196
+ ui.info "Mapping Successful"
197
+
198
+ # make a file backed optical drive
199
+ ui.info "Creating virtual file backed optical device"
200
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"mkvdev -fbo -vadapter #{vhost_name}\""
201
+ vopt_name = run_remote_command(ssh, command).split(" ")[0]
202
+ ui.info "Created device #{vopt_name}"
203
+
204
+ # load the iso
205
+ ui.info "Loading disk in optical drive"
206
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"loadopt -vtd #{vopt_name} -disk #{config[:disk_name]}\""
207
+ output = run_remote_command(ssh, command)
208
+ ui.info "Loading Successful"
209
+
210
+ # create logical volume
211
+ ui.info "Creating logical volume"
212
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"mklv -lv #{config[:name]} rootvg 50G\""
213
+ lv_name = run_remote_command(ssh, command)
214
+ ui.info "Created logical volume #{lv_name}"
215
+
216
+ # attach it
217
+ ui.info "Attaching lv to lpar"
218
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"mkvdev -vdev #{config[:name]} -vadapter #{vhost_name}\""
219
+ vtscsi_name = run_remote_command(ssh, command).split(" ")[0]
220
+ ui.info "Attach Successful as #{vtscsi_name}"
221
+
222
+ # save the virtual io server profile
223
+ ui.info "Activating virtual io server profile"
224
+ command = "mksyscfg -r prof -m #{config[:virtual_server]} -o save -p #{config[:vios]} -n `lssyscfg -r lpar -m #{config[:virtual_server]} --filter \"lpar_names=#{config[:vios]}\" -F curr_profile` --force"
225
+ output = run_remote_command(ssh, command)
226
+ ui.info "Activation Successful"
227
+
228
+ # reload the lpar so it knows it has new devices
229
+ ui.info "Reload virtual io server to re-read devices"
230
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"cfgdev\""
231
+ output = run_remote_command(ssh, command)
232
+ ui.info "Reload Successful"
233
+
234
+ # could start it up here, we'll see
235
+ ui.info "Boot lpar in SMS mode"
236
+ command = "chsysstate -r lpar -m #{config[:virtual_server]} -o on -f #{config[:profile]} -b sms -n #{config[:name]}"
237
+ output = run_remote_command(ssh, command)
238
+ unless output.nil?
239
+ ui.info output.to_s
240
+ end
241
+ ui.info "Boot Successful"
242
+ end
243
+ end
244
+
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,168 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014-2016 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "chef/knife"
19
+ require "chef/knife/lpar_base"
20
+
21
+ class Chef
22
+ class Knife
23
+ class LparDelete < Knife
24
+ include Chef::Knife::LparBase
25
+
26
+ banner "knife lpar delete HMC [options]"
27
+
28
+ option :name,
29
+ :short => "-n NAME",
30
+ :long => "--name",
31
+ :description => "LPAR Name"
32
+
33
+ option :virtual_server,
34
+ :short => "-v SERVER",
35
+ :long => "--virtual-server",
36
+ :description => "Virtual Server Name"
37
+
38
+ option :vios,
39
+ :long => "--vios NAME",
40
+ :description => "Virtual I/O Server LPAR Name"
41
+
42
+ option :help,
43
+ :long => "--help",
44
+ :description => "Prints this menu"
45
+
46
+ #
47
+ # Run the plugin
48
+ #
49
+ def run
50
+ read_and_validate_params
51
+ @password = get_password
52
+ delete_lpar
53
+ end
54
+
55
+ #
56
+ # Reads the input parameters and validates them.
57
+ # Will exit if it encounters an error
58
+ #
59
+ def read_and_validate_params
60
+ if @name_args.length < 1
61
+ show_usage
62
+ exit 1
63
+ end
64
+
65
+ if config[:name].nil? ||
66
+ config[:vios].nil? ||
67
+ config[:virtual_server].nil?
68
+ show_usage
69
+ exit 1
70
+ end
71
+ end
72
+
73
+ def delete_lpar
74
+ Net::SSH.start(@name_args[0], "hscroot", :password => @password) do |ssh|
75
+ # some background checks
76
+
77
+ # check for existing lpar with name
78
+ ui.info "Verifying #{config[:name]} exists"
79
+ command = "lssyscfg -m #{config[:virtual_server]} -F name -r lpar --filter \"lpar_names=#{config[:name]}\""
80
+ output = run_remote_command(ssh, command)
81
+ unless output.eql? config[:name]
82
+ ui.fatal output
83
+ Kernel.exit(1)
84
+ end
85
+
86
+ # Check to see if it's running
87
+ ui.info "Verifying #{config[:name]} is not running"
88
+ command = "lssyscfg -m #{config[:virtual_server]} -F state -r lpar --filter \"lpar_names=#{config[:name]}\""
89
+ output = run_remote_command(ssh, command)
90
+ unless output.eql? "Not Activated"
91
+ ui.fatal output
92
+ Kernel.exit(1)
93
+ end
94
+
95
+ # first let's find the host mapping
96
+ ui.info "Searching for host mapping"
97
+ command = "lssyscfg -m #{config[:virtual_server]} --filter \"lpar_names=#{config[:name]}\" -F lpar_id -r lpar"
98
+ output = run_remote_command(ssh, command)
99
+ # and of course it doesn't match, 0 based vs 1 based counting
100
+ vhost = output.to_i - 1
101
+ vhost_name = "vhost#{vhost}"
102
+ print_with_output("Found host id of #{output} - mapping to #{vhost_name}", nil)
103
+
104
+ # mapping for the drive
105
+ ui.info "Searching for vscsi mapping"
106
+ command = "lssyscfg -m #{config[:virtual_server]} -r prof --filter \"lpar_names=#{config[:name]}\" -F virtual_scsi_adapters"
107
+ output = run_remote_command(ssh, command)
108
+ vscsi_id = output.match('.*\/.*\/.*\/.*\/(.*)\/.*')[1]
109
+ print_with_output("Found vscsi mapping #{vscsi_id}", output)
110
+
111
+ # find the mapping for the vopt
112
+ ui.info "Searching for vtopt mapping"
113
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"lsmap -vadapter #{vhost_name} -type file_opt -field vtd -fmt \\\":\\\"\""
114
+ vtopt_id = run_remote_command(ssh, command)
115
+ print_with_output("Found vtopt mapping #{vtopt_id}", output)
116
+
117
+ # find lv mapping
118
+ ui.info "Searching for logical volume mapping"
119
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"lsmap -vadapter #{vhost_name} -type lv -field vtd -fmt \\\":\\\"\""
120
+ lv_id = run_remote_command(ssh, command)
121
+ print_with_output("Found lv mapping #{lv_id}", output)
122
+
123
+ # find lv backing device
124
+ ui.info "Searching for lv backing device"
125
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"lsmap -vadapter #{vhost_name} -type lv -field backing -fmt \\\":\\\"\""
126
+ backing_device = run_remote_command(ssh, command)
127
+ print_with_output("Found device #{backing_device}")
128
+
129
+ # now delete the file backed optical drive mapping
130
+ ui.info "Removing #{vtopt_id}"
131
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"rmvdev -vtd #{vtopt_id}\""
132
+ output = run_remote_command(ssh, command)
133
+ print_with_output("#{vtopt_id} Removed", output)
134
+
135
+ # now delete the vtscsi device
136
+ ui.info "Removing vscsi #{lv_id}"
137
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"rmvdev -vtd #{lv_id}\""
138
+ output = run_remote_command(ssh, command)
139
+ print_with_output("#{lv_id} Removed", output)
140
+
141
+ # now delete the logical volume
142
+ ui.info "Removing lv #{backing_device}"
143
+ command = "viosvrcmd -m #{config[:virtual_server]} -p #{config[:vios]} -c \"rmlv -f #{backing_device}\""
144
+ output = run_remote_command(ssh, command)
145
+ print_with_output("#{backing_device} Removed", output)
146
+
147
+ # now that we know the id, let's remove it from the virtual io server
148
+ ui.info "Removing vtscsi mapping from vios"
149
+ command = "chhwres -r virtualio -m #{config[:virtual_server]} -o r -p #{config[:vios]} --rsubtype scsi -s #{vscsi_id}"
150
+ output = run_remote_command(ssh, command)
151
+ print_with_output("Mapping Removed", output)
152
+
153
+ # save the virtual io server profile
154
+ ui.info "Saving updated vios profile on #{config[:vios]}"
155
+ command = "mksyscfg -r prof -m #{config[:virtual_server]} -o save -p #{config[:vios]} -n `lssyscfg -r lpar -m #{config[:virtual_server]} --filter \"lpar_names=#{config[:vios]}\" -F curr_profile` --force"
156
+ output = run_remote_command(ssh, command)
157
+ print_with_output("Profile Saved", output)
158
+
159
+ # now remove the lpar completely
160
+ ui.info "Removing #{config[:name]} completely"
161
+ command = "rmsyscfg -r lpar -m #{config[:virtual_server]} -n #{config[:name]}"
162
+ output = run_remote_command(ssh, command)
163
+ print_with_output("#{config[:name]} Terminated", output)
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end