ibm_power_hmc 0.18.0 → 0.19.0

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.
@@ -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