ibm_power_hmc 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,72 +2,8 @@
2
2
 
3
3
  require 'erb'
4
4
 
5
- # Module for IBM HMC Rest API Client
6
5
  module IbmPowerHmc
7
- class Error < StandardError; end
8
-
9
- ##
10
- # HMC REST Client connection.
11
6
  class Connection
12
- ##
13
- # @!method initialize(host:, password:, username: "hscroot", port: 12_443, validate_ssl: true, timeout: 60)
14
- # Create a new HMC connection.
15
- #
16
- # @param host [String] Hostname of the HMC.
17
- # @param password [String] Password.
18
- # @param username [String] User name.
19
- # @param port [Integer] TCP port number.
20
- # @param validate_ssl [Boolean] Verify SSL certificates.
21
- # @param timeout [Integer] The default HTTP timeout in seconds.
22
- def initialize(host:, password:, username: "hscroot", port: 12_443, validate_ssl: true, timeout: 60)
23
- @hostname = "#{host}:#{port}"
24
- @username = username
25
- @password = password
26
- @verify_ssl = validate_ssl
27
- @api_session_token = nil
28
- @timeout = timeout
29
- end
30
-
31
- ##
32
- # @!method logon
33
- # Establish a trusted session with the Web Services APIs.
34
- # @return [String] The X-API-Session token.
35
- def logon
36
- method_url = "/rest/api/web/Logon"
37
- headers = {
38
- :content_type => "application/vnd.ibm.powervm.web+xml; type=LogonRequest"
39
- }
40
- doc = REXML::Document.new("")
41
- doc.add_element("LogonRequest", "schemaVersion" => "V1_1_0")
42
- doc.root.add_namespace("http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/")
43
- doc.root.add_element("UserID").text = @username
44
- doc.root.add_element("Password").text = @password
45
-
46
- @api_session_token = ""
47
- response = request(:put, method_url, headers, doc.to_s)
48
- doc = REXML::Document.new(response.body)
49
- elem = doc.elements["LogonResponse/X-API-Session"]
50
- raise Error, "LogonResponse/X-API-Session not found" if elem.nil?
51
-
52
- @api_session_token = elem.text
53
- end
54
-
55
- ##
56
- # @!method logoff
57
- # Close the session.
58
- def logoff
59
- # Don't want to trigger automatic logon here!
60
- return if @api_session_token.nil?
61
-
62
- method_url = "/rest/api/web/Logon"
63
- begin
64
- request(:delete, method_url)
65
- rescue
66
- # Ignore exceptions as this is best effort attempt to log off.
67
- end
68
- @api_session_token = nil
69
- end
70
-
71
7
  ##
72
8
  # @!method management_console
73
9
  # Retrieve information about the management console.
@@ -231,6 +167,16 @@ module IbmPowerHmc
231
167
  end
232
168
  end
233
169
 
170
+ ##
171
+ # @!method lpar_delete(lpar_uuid)
172
+ # Delete a logical partition.
173
+ # @param lpar_uuid [String] The UUID of the logical partition to delete.
174
+ def lpar_delete(lpar_uuid)
175
+ method_url = "/rest/api/uom/LogicalPartition/#{lpar_uuid}"
176
+ request(:delete, method_url)
177
+ # Returns HTTP 204 if ok
178
+ end
179
+
234
180
  ##
235
181
  # @!method vioses(sys_uuid = nil, search = nil, group_name = nil, permissive = true)
236
182
  # Retrieve the list of virtual I/O servers managed by the HMC.
@@ -366,6 +312,19 @@ module IbmPowerHmc
366
312
  network_adapter("VirtualIOServer", vios_uuid, netadap_uuid)
367
313
  end
368
314
 
315
+ def network_adapter(obj_type, lpar_uuid, netadap_uuid)
316
+ if netadap_uuid.nil?
317
+ method_url = "/rest/api/uom/#{obj_type}/#{lpar_uuid}/ClientNetworkAdapter"
318
+ response = request(:get, method_url)
319
+ FeedParser.new(response.body).objects(:ClientNetworkAdapter)
320
+ else
321
+ method_url = "/rest/api/uom/#{obj_type}/#{lpar_uuid}/ClientNetworkAdapter/#{netadap_uuid}"
322
+ response = request(:get, method_url)
323
+ Parser.new(response.body).object(:ClientNetworkAdapter)
324
+ end
325
+ end
326
+ private :network_adapter
327
+
369
328
  ##
370
329
  # @!method sriov_elp_lpar(lpar_uuid, sriov_elp_uuid = nil)
371
330
  # Retrieve one or all SR-IOV ethernet logical ports attached to a logical partition.
@@ -373,19 +332,32 @@ module IbmPowerHmc
373
332
  # @param sriov_elp_uuid [String] UUID of the port to match (returns all ports if omitted).
374
333
  # @return [Array<IbmPowerHmc::SRIOVEthernetLogicalPort>, IbmPowerHmc::SRIOVEthernetLogicalPort] The list of ports.
375
334
  def sriov_elp_lpar(lpar_uuid, sriov_elp_uuid = nil)
376
- sriov_ethernet_port("LogicalPartition", lpar_uuid, sriov_elp_uuid)
335
+ sriov_elp("LogicalPartition", lpar_uuid, sriov_elp_uuid)
377
336
  end
378
337
 
379
338
  ##
380
- # @!method network_adapter_vios(vios_uuid, sriov_elp_uuid = nil)
339
+ # @!method sriov_elp_vios(vios_uuid, sriov_elp_uuid = nil)
381
340
  # Retrieve one or all SR-IOV ethernet logical ports attached to a Virtual I/O Server.
382
341
  # @param vios_uuid [String] UUID of the Virtual I/O Server.
383
342
  # @param sriov_elp_uuid [String] UUID of the port to match (returns all ports if omitted).
384
343
  # @return [Array<IbmPowerHmc::SRIOVEthernetLogicalPort>, IbmPowerHmc::SRIOVEthernetLogicalPort] The list of ports.
385
344
  def sriov_elp_vios(vios_uuid, sriov_elp_uuid = nil)
386
- sriov_ethernet_port("VirtualIOServer", vios_uuid, sriov_elp_uuid)
345
+ sriov_elp("VirtualIOServer", vios_uuid, sriov_elp_uuid)
387
346
  end
388
347
 
348
+ def sriov_elp(obj_type, lpar_uuid, sriov_elp_uuid)
349
+ if sriov_elp_uuid.nil?
350
+ method_url = "/rest/api/uom/#{obj_type}/#{lpar_uuid}/SRIOVEthernetLogicalPort"
351
+ response = request(:get, method_url)
352
+ FeedParser.new(response.body).objects(:SRIOVEthernetLogicalPort)
353
+ else
354
+ method_url = "/rest/api/uom/#{obj_type}/#{lpar_uuid}/SRIOVEthernetLogicalPort/#{sriov_elp_uuid}"
355
+ response = request(:get, method_url)
356
+ Parser.new(response.body).object(:SRIOVEthernetLogicalPort)
357
+ end
358
+ end
359
+ private :sriov_elp
360
+
389
361
  ##
390
362
  # @!method vnic_dedicated(lpar_uuid, vnic_uuid = nil)
391
363
  # Retrieve one or all dedicated virtual network interface controller (vNIC) attached to a logical partition.
@@ -531,172 +503,6 @@ module IbmPowerHmc
531
503
  end
532
504
  end
533
505
 
534
- ##
535
- # @!method templates_summary(draft = false)
536
- # Retrieve the list of partition template summaries.
537
- # @param draft [Boolean] Retrieve draft templates as well
538
- # @return [Array<IbmPowerHmc::PartitionTemplateSummary>] The list of partition template summaries.
539
- def templates_summary(draft = false)
540
- method_url = "/rest/api/templates/PartitionTemplate#{'?draft=false' unless draft}"
541
- response = request(:get, method_url)
542
- FeedParser.new(response.body).objects(:PartitionTemplateSummary)
543
- end
544
-
545
- ##
546
- # @!method templates(draft = false)
547
- # Retrieve the list of partition templates.
548
- # @param draft [Boolean] Retrieve draft templates as well
549
- # @return [Array<IbmPowerHmc::PartitionTemplate>] The list of partition templates.
550
- def templates(draft = false)
551
- method_url = "/rest/api/templates/PartitionTemplate?detail=full#{'&draft=false' unless draft}"
552
- response = request(:get, method_url)
553
- FeedParser.new(response.body).objects(:PartitionTemplate)
554
- end
555
-
556
- ##
557
- # @!method template(template_uuid)
558
- # Retrieve details for a particular partition template.
559
- # @param template_uuid [String] UUID of the partition template.
560
- # @return [IbmPowerHmc::PartitionTemplate] The partition template.
561
- def template(template_uuid)
562
- method_url = "/rest/api/templates/PartitionTemplate/#{template_uuid}"
563
- response = request(:get, method_url)
564
- Parser.new(response.body).object(:PartitionTemplate)
565
- end
566
-
567
- ##
568
- # @!method capture_lpar(lpar_uuid, sys_uuid, template_name, sync = true)
569
- # Capture partition configuration as template.
570
- # @param lpar_uuid [String] The UUID of the logical partition.
571
- # @param sys_uuid [String] The UUID of the managed system.
572
- # @param template_name [String] The name to be given for the new template.
573
- # @param sync [Boolean] Start the job and wait for its completion.
574
- # @return [IbmPowerHmc::HmcJob] The HMC job.
575
- def capture_lpar(lpar_uuid, sys_uuid, template_name, sync = true)
576
- # Need to include session token in payload so make sure we are logged in
577
- logon if @api_session_token.nil?
578
- method_url = "/rest/api/templates/PartitionTemplate/do/capture"
579
- params = {
580
- "TargetUuid" => lpar_uuid,
581
- "NewTemplateName" => template_name,
582
- "ManagedSystemUuid" => sys_uuid,
583
- "K_X_API_SESSION_MEMENTO" => @api_session_token
584
- }
585
- job = HmcJob.new(self, method_url, "Capture", "PartitionTemplate", params)
586
- job.run if sync
587
- job
588
- end
589
-
590
- ##
591
- # @!method template_check(template_uuid, target_sys_uuid, sync = true)
592
- # Start Template Check job (first of three steps to deploy an LPAR from a Template).
593
- # @param template_uuid [String] The UUID of the Template to deploy an LPAR from.
594
- # @param target_sys_uuid [String] The UUID of the Managed System to deploy the LPAR on.
595
- # @param sync [Boolean] Start the job and wait for its completion.
596
- # @return [IbmPowerHmc::HmcJob] The HMC job.
597
- def template_check(template_uuid, target_sys_uuid, sync = true)
598
- # Need to include session token in payload so make sure we are logged in
599
- logon if @api_session_token.nil?
600
- method_url = "/rest/api/templates/PartitionTemplate/#{template_uuid}/do/check"
601
- params = {
602
- "TargetUuid" => target_sys_uuid,
603
- "K_X_API_SESSION_MEMENTO" => @api_session_token
604
- }
605
- job = HmcJob.new(self, method_url, "Check", "PartitionTemplate", params)
606
- job.run if sync
607
- job
608
- end
609
-
610
- ##
611
- # @!method template_transform(draft_template_uuid, target_sys_uuid, sync = true)
612
- # Start Template Transform job (second of three steps to deploy an LPAR from a Template).
613
- # @param draft_template_uuid [String] The UUID of the Draft Template created by the Template Check job.
614
- # @param target_sys_uuid [String] The UUID of the Managed System to deploy the LPAR on.
615
- # @param sync [Boolean] Start the job and wait for its completion.
616
- # @return [IbmPowerHmc::HmcJob] The HMC job.
617
- def template_transform(draft_template_uuid, target_sys_uuid, sync = true)
618
- # Need to include session token in payload so make sure we are logged in
619
- logon if @api_session_token.nil?
620
- method_url = "/rest/api/templates/PartitionTemplate/#{draft_template_uuid}/do/transform"
621
- params = {
622
- "TargetUuid" => target_sys_uuid,
623
- "K_X_API_SESSION_MEMENTO" => @api_session_token
624
- }
625
- job = HmcJob.new(self, method_url, "Transform", "PartitionTemplate", params)
626
- job.run if sync
627
- job
628
- end
629
-
630
- ##
631
- # @!method template_deploy(draft_template_uuid, target_sys_uuid, sync = true)
632
- # Start Template Deploy job (last of three steps to deploy an LPAR from a Template).
633
- # @param draft_template_uuid [String] The UUID of the Draft Template created by the Template Check job.
634
- # @param target_sys_uuid [String] The UUID of the Managed System to deploy the LPAR on.
635
- # @param sync [Boolean] Start the job and wait for its completion.
636
- # @return [IbmPowerHmc::HmcJob] The HMC job.
637
- def template_deploy(draft_template_uuid, target_sys_uuid, sync = true)
638
- # Need to include session token in payload so make sure we are logged in
639
- logon if @api_session_token.nil?
640
- method_url = "/rest/api/templates/PartitionTemplate/#{draft_template_uuid}/do/deploy"
641
- params = {
642
- "TargetUuid" => target_sys_uuid,
643
- "TemplateUuid" => draft_template_uuid,
644
- "K_X_API_SESSION_MEMENTO" => @api_session_token
645
- }
646
- job = HmcJob.new(self, method_url, "Deploy", "PartitionTemplate", params)
647
- job.run if sync
648
- job
649
- end
650
-
651
- ##
652
- # @!method template_provision(template_uuid, target_sys_uuid, changes)
653
- # Deploy Logical Partition from a Template (performs Check, Transform and Deploy steps in a single method).
654
- # @param template_uuid [String] The UUID of the Template to deploy an LPAR from.
655
- # @param target_sys_uuid [String] The UUID of the Managed System to deploy the LPAR on.
656
- # @param changes [Hash] Modifications to apply to the Template before deploying Logical Partition.
657
- # @return [String] The UUID of the deployed Logical Partition.
658
- def template_provision(template_uuid, target_sys_uuid, changes)
659
- draft_uuid = template_check(template_uuid, target_sys_uuid).results["TEMPLATE_UUID"]
660
- template_transform(draft_uuid, target_sys_uuid)
661
- template_modify(draft_uuid, changes)
662
- template_deploy(draft_uuid, target_sys_uuid).results["PartitionUuid"]
663
- end
664
-
665
- ##
666
- # @!method template_modify(template_uuid, changes)
667
- # Modify a template.
668
- # @param template_uuid [String] UUID of the partition template to modify.
669
- # @param changes [Hash] Hash of changes to make.
670
- def template_modify(template_uuid, changes)
671
- method_url = "/rest/api/templates/PartitionTemplate/#{template_uuid}"
672
-
673
- # Templates have no href so need to use modify_object_url.
674
- modify_object_url(method_url) do
675
- template(template_uuid).tap do |obj|
676
- changes.each do |key, value|
677
- obj.send("#{key}=", value)
678
- end
679
- end
680
- end
681
- end
682
-
683
- ##
684
- # @!method template_copy(template_uuid, new_name)
685
- # Copy existing template to a new one.
686
- # @param template_uuid [String] UUID of the partition template to copy.
687
- # @param new_name [String] Name of the new template.
688
- # @return [IbmPowerHmc::PartitionTemplate] The new partition template.
689
- def template_copy(template_uuid, new_name)
690
- method_url = "/rest/api/templates/PartitionTemplate"
691
- headers = {
692
- :content_type => "application/vnd.ibm.powervm.templates+xml;type=PartitionTemplate"
693
- }
694
- original = template(template_uuid)
695
- original.name = new_name
696
- response = request(:put, method_url, headers, original.xml.to_s)
697
- Parser.new(response.body).object(:PartitionTemplate)
698
- end
699
-
700
506
  ##
701
507
  # @!method poweron_lpar(lpar_uuid, params = {}, sync = true)
702
508
  # Power on a logical partition.
@@ -840,167 +646,5 @@ module IbmPowerHmc
840
646
  e
841
647
  end.compact
842
648
  end
843
-
844
- ##
845
- # @!method usertask(uuid = true)
846
- # Retrieve details of an event of type "user task".
847
- # @param uuid [String] UUID of user task.
848
- # @return [Hash] Hash of user task attributes.
849
- def usertask(uuid)
850
- method_url = "/rest/api/ui/UserTask/#{uuid}"
851
- response = request(:get, method_url)
852
- j = JSON.parse(response.body)
853
- if j['status'].eql?("Completed")
854
- case j['key']
855
- when "TEMPLATE_PARTITION_SAVE", "TEMPLATE_PARTITION_SAVE_AS", "TEMPLATE_PARTITION_CAPTURE"
856
- j['template_uuid'] = templates_summary.find { |t| t.name.eql?(j['labelParams'].first) }&.uuid
857
- end
858
- end
859
- j
860
- end
861
-
862
- ##
863
- # @!method schema(type)
864
- # Retrieve the XML schema file for a given object type.
865
- # @param type [String] The object type (e.g. "LogicalPartition", "inc/Types")
866
- # @return [REXML::Document] The XML schema file.
867
- def schema(type)
868
- method_url = "/rest/api/web/schema/#{type}.xsd"
869
- response = request(:get, method_url)
870
- REXML::Document.new(response.body)
871
- end
872
-
873
- class HttpError < Error
874
- attr_reader :status, :uri, :reason, :message, :original_exception
875
-
876
- ##
877
- # @!method initialize(err)
878
- # Create a new HttpError exception.
879
- # @param err [RestClient::Exception] The REST client exception.
880
- def initialize(err)
881
- super
882
- @original_exception = err
883
- @status = err.http_code
884
- @message = err.message
885
-
886
- # Try to parse body as an HttpErrorResponse.
887
- unless err.response.nil?
888
- begin
889
- resp = Parser.new(err.response.body).object(:HttpErrorResponse)
890
- @uri = resp.uri
891
- @reason = resp.reason
892
- @message = resp.message
893
- rescue
894
- # not an XML body
895
- end
896
- end
897
- end
898
-
899
- def to_s
900
- "msg=\"#{@message}\" status=\"#{@status}\" reason=\"#{@reason}\" uri=#{@uri}"
901
- end
902
- end
903
-
904
- ##
905
- # @!method request(method, url, headers = {}, payload = nil)
906
- # Perform a REST API request.
907
- # @param method [String] The HTTP method.
908
- # @param url [String] The method URL.
909
- # @param headers [Hash] HTTP headers.
910
- # @param payload [String] HTTP request payload.
911
- # @return [RestClient::Response] The response from the HMC.
912
- def request(method, url, headers = {}, payload = nil)
913
- logon if @api_session_token.nil?
914
- reauth = false
915
- # Check for relative URLs
916
- url = "https://#{@hostname}#{url}" if url.start_with?("/")
917
- begin
918
- headers = headers.merge("X-API-Session" => @api_session_token)
919
- RestClient::Request.execute(
920
- :method => method,
921
- :url => url,
922
- :verify_ssl => @verify_ssl,
923
- :payload => payload,
924
- :headers => headers,
925
- :timeout => @timeout
926
- )
927
- rescue RestClient::Exception => e
928
- # Do not retry on failed logon attempts.
929
- if e.http_code == 401 && @api_session_token != "" && !reauth
930
- # Try to reauth.
931
- reauth = true
932
- logon
933
- retry
934
- end
935
- raise HttpError.new(e), "REST request failed"
936
- end
937
- end
938
-
939
- # @!method modify_object(headers = {}, attempts = 5)
940
- # Post an IbmPowerHmc::AbstractRest object iteratively using ETag.
941
- # @param headers [Hash] HTTP headers.
942
- # @param attempts [Integer] Maximum number of retries.
943
- # @yieldreturn [IbmPowerHmc::AbstractRest] The object to modify.
944
- def modify_object(headers = {}, attempts = 5, &block)
945
- modify_object_url(nil, headers, attempts, &block)
946
- end
947
-
948
- private
949
-
950
- def modify_object_url(method_url = nil, headers = {}, attempts = 5)
951
- while attempts > 0
952
- obj = yield
953
- raise "object has no href" if method_url.nil? && (!obj.kind_of?(AbstractRest) || obj.href.nil?)
954
-
955
- # Use ETag to ensure object has not changed.
956
- headers = headers.merge("If-Match" => obj.etag, :content_type => obj.content_type)
957
- begin
958
- request(:post, method_url.nil? ? obj.href.path : method_url, headers, obj.xml.to_s)
959
- break
960
- rescue HttpError => e
961
- attempts -= 1
962
- # Will get 412 ("Precondition Failed") if ETag mismatches.
963
- raise if e.status != 412 || attempts == 0
964
- end
965
- end
966
- end
967
-
968
- ##
969
- # @!method network_adapter(vm_type, lpar_uuid, netadap_uuid)
970
- # Retrieve one or all virtual ethernet network adapters attached to a Logical Partition or a Virtual I/O Server.
971
- # @param vm_type [String] "LogicalPartition" or "VirtualIOServer".
972
- # @param lpar_uuid [String] UUID of the Logical Partition or the Virtual I/O Server.
973
- # @param netadap_uuid [String] UUID of the adapter to match (returns all adapters if nil).
974
- # @return [Array<IbmPowerHmc::ClientNetworkAdapter>, IbmPowerHmc::ClientNetworkAdapter] The list of network adapters.
975
- def network_adapter(vm_type, lpar_uuid, netadap_uuid)
976
- if netadap_uuid.nil?
977
- method_url = "/rest/api/uom/#{vm_type}/#{lpar_uuid}/ClientNetworkAdapter"
978
- response = request(:get, method_url)
979
- FeedParser.new(response.body).objects(:ClientNetworkAdapter)
980
- else
981
- method_url = "/rest/api/uom/#{vm_type}/#{lpar_uuid}/ClientNetworkAdapter/#{netadap_uuid}"
982
- response = request(:get, method_url)
983
- Parser.new(response.body).object(:ClientNetworkAdapter)
984
- end
985
- end
986
-
987
- ##
988
- # @!method sriov_ethernet_port(vm_type, lpar_uuid, sriov_elp_uuid)
989
- # Retrieve one or all SR-IOV Ethernet loical ports attached to a Logical Partition or a Virtual I/O Server.
990
- # @param vm_type [String] "LogicalPartition" or "VirtualIOServer".
991
- # @param lpar_uuid [String] UUID of the Logical Partition or the Virtual I/O Server.
992
- # @param sriov_elp_uuid [String] UUID of the port to match (returns all ports if nil).
993
- # @return [Array<IbmPowerHmc::SRIOVEthernetLogicalPort>, IbmPowerHmc::SRIOVEthernetLogicalPort] The list of ports.
994
- def sriov_ethernet_port(vm_type, lpar_uuid, sriov_elp_uuid)
995
- if sriov_elp_uuid.nil?
996
- method_url = "/rest/api/uom/#{vm_type}/#{lpar_uuid}/SRIOVEthernetLogicalPort"
997
- response = request(:get, method_url)
998
- FeedParser.new(response.body).objects(:SRIOVEthernetLogicalPort)
999
- else
1000
- method_url = "/rest/api/uom/#{vm_type}/#{lpar_uuid}/SRIOVEthernetLogicalPort/#{sriov_elp_uuid}"
1001
- response = request(:get, method_url)
1002
- Parser.new(response.body).object(:SRIOVEthernetLogicalPort)
1003
- end
1004
- end
1005
649
  end
1006
650
  end