jellyfish-manageiq 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/README.md +109 -0
  4. data/Rakefile +25 -0
  5. data/app/assets/images/jellyfish_manageiq/products/apache.png +0 -0
  6. data/app/assets/images/jellyfish_manageiq/products/aws_ec2.png +0 -0
  7. data/app/assets/images/jellyfish_manageiq/products/aws_rds.png +0 -0
  8. data/app/assets/images/jellyfish_manageiq/products/aws_s3.png +0 -0
  9. data/app/assets/images/jellyfish_manageiq/products/bugzilla.png +0 -0
  10. data/app/assets/images/jellyfish_manageiq/products/confluence.png +0 -0
  11. data/app/assets/images/jellyfish_manageiq/products/database.png +0 -0
  12. data/app/assets/images/jellyfish_manageiq/products/dna.png +0 -0
  13. data/app/assets/images/jellyfish_manageiq/products/exchange.png +0 -0
  14. data/app/assets/images/jellyfish_manageiq/products/f5.png +0 -0
  15. data/app/assets/images/jellyfish_manageiq/products/firewall.png +0 -0
  16. data/app/assets/images/jellyfish_manageiq/products/hadoop.png +0 -0
  17. data/app/assets/images/jellyfish_manageiq/products/java.png +0 -0
  18. data/app/assets/images/jellyfish_manageiq/products/jira.png +0 -0
  19. data/app/assets/images/jellyfish_manageiq/products/kb.png +0 -0
  20. data/app/assets/images/jellyfish_manageiq/products/man.png +0 -0
  21. data/app/assets/images/jellyfish_manageiq/products/mean.png +0 -0
  22. data/app/assets/images/jellyfish_manageiq/products/mssql.png +0 -0
  23. data/app/assets/images/jellyfish_manageiq/products/netapp.png +0 -0
  24. data/app/assets/images/jellyfish_manageiq/products/oracle.png +0 -0
  25. data/app/assets/images/jellyfish_manageiq/products/php.png +0 -0
  26. data/app/assets/images/jellyfish_manageiq/products/postgresql.png +0 -0
  27. data/app/assets/images/jellyfish_manageiq/products/rails.png +0 -0
  28. data/app/assets/images/jellyfish_manageiq/products/redhat.png +0 -0
  29. data/app/assets/images/jellyfish_manageiq/products/teradata.png +0 -0
  30. data/app/assets/images/jellyfish_manageiq/products/ubuntu.png +0 -0
  31. data/app/assets/images/jellyfish_manageiq/products/windows.png +0 -0
  32. data/app/assets/images/jellyfish_manageiq/products/woman.png +0 -0
  33. data/app/assets/javascripts/jellyfish_manageiq/application.js +13 -0
  34. data/app/assets/javascripts/jellyfish_manageiq/products_admin_controller.js +63 -0
  35. data/app/assets/stylesheets/jellyfish_manageiq/application.css +15 -0
  36. data/app/controllers/manageiq/automate_controller.rb +61 -0
  37. data/app/controllers/manageiq/order_items_controller.rb +64 -0
  38. data/app/helpers/application_helper.rb +2 -0
  39. data/app/models/manage_iq_client.rb +12 -0
  40. data/app/models/manage_iq_client/base.rb +61 -0
  41. data/app/models/manage_iq_client/cluster.rb +9 -0
  42. data/app/models/manage_iq_client/datastore.rb +9 -0
  43. data/app/models/manage_iq_client/host.rb +9 -0
  44. data/app/models/manage_iq_client/policy.rb +9 -0
  45. data/app/models/manage_iq_client/policy_profile.rb +9 -0
  46. data/app/models/manage_iq_client/provider.rb +9 -0
  47. data/app/models/manage_iq_client/resource.rb +82 -0
  48. data/app/models/manage_iq_client/resource_pool.rb +9 -0
  49. data/app/models/manage_iq_client/server.rb +34 -0
  50. data/app/models/manage_iq_client/service.rb +9 -0
  51. data/app/models/manage_iq_client/service_catalog.rb +9 -0
  52. data/app/models/manage_iq_client/service_template.rb +9 -0
  53. data/app/models/manage_iq_client/template.rb +25 -0
  54. data/app/models/manage_iq_client/virtual_machine.rb +27 -0
  55. data/app/models/manage_iq_client/zone.rb +9 -0
  56. data/app/policies/manageiq/order_item_policy.rb +16 -0
  57. data/app/views/manageiq/automate/catalog_item_initialization.html.erb +0 -0
  58. data/app/views/manageiq/automate/create_chef_node.html.erb +97 -0
  59. data/app/views/manageiq/automate/create_ec2.html.erb +140 -0
  60. data/app/views/manageiq/automate/create_rds.html.erb +146 -0
  61. data/app/views/manageiq/automate/create_s3.html.erb +100 -0
  62. data/app/views/manageiq/automate/create_ses.html.erb +114 -0
  63. data/app/views/manageiq/automate/create_vmware_vm.html.erb +102 -0
  64. data/app/views/manageiq/automate/provision_rds.html.erb +130 -0
  65. data/app/views/manageiq/automate/retire_ec2.html.erb +96 -0
  66. data/app/views/manageiq/automate/retire_rds.html.erb +117 -0
  67. data/app/views/manageiq/automate/retire_s3.html.erb +93 -0
  68. data/app/views/manageiq/automate/retire_ses.html.erb +98 -0
  69. data/app/views/manageiq/automate/retire_vmware_vm.html.erb +70 -0
  70. data/app/views/manageiq/automate/update_servicemix_and_chef.html.erb +364 -0
  71. data/config/initializers/manage_iq_client.rb +9 -0
  72. data/config/initializers/product_types.rb +6 -0
  73. data/config/initializers/provisioners.rb +9 -0
  74. data/config/initializers/task_scheduler.rb +12 -0
  75. data/config/product_questions/big_data.json +50 -0
  76. data/config/product_questions/database.json +79 -0
  77. data/config/product_questions/infrastructure.json +49 -0
  78. data/config/product_questions/storage.json +57 -0
  79. data/config/provisioners.json +6 -0
  80. data/config/routes.rb +38 -0
  81. data/db/migrate/20150513221625_create_jellyfish_manageiq_database_products.rb +16 -0
  82. data/db/migrate/20150513221938_create_jellyfish_manageiq_big_data_products.rb +14 -0
  83. data/db/migrate/20150513222020_create_jellyfish_manageiq_infrastructure_products.rb +13 -0
  84. data/db/migrate/20150513222056_create_jellyfish_manageiq_storage_products.rb +13 -0
  85. data/lib/jellyfish/manageiq.rb +34 -0
  86. data/lib/jellyfish/manageiq/big_data.rb +6 -0
  87. data/lib/jellyfish/manageiq/databases.rb +6 -0
  88. data/lib/jellyfish/manageiq/engine.rb +19 -0
  89. data/lib/jellyfish/manageiq/infrastructure.rb +6 -0
  90. data/lib/jellyfish/manageiq/provisioner.rb +115 -0
  91. data/lib/jellyfish/manageiq/storage.rb +6 -0
  92. data/lib/jellyfish/manageiq/version.rb +5 -0
  93. data/lib/tasks/pollvms.rake +42 -0
  94. metadata +360 -0
@@ -0,0 +1,117 @@
1
+ # Description: This MIQ Method deletes an RDS instance
2
+ # From an instance collection
3
+
4
+ require 'aws-sdk'
5
+ require 'net/http'
6
+ require 'securerandom'
7
+ require 'uri/http'
8
+ require 'json'
9
+
10
+ def send_order_status(referer, headers, status, order_id, information, message = '')
11
+ path = "/order_items/#{order_id}/provision_update"
12
+ host = URI.parse(referer).host
13
+ url = "http://#{host}#{path}"
14
+ uri = URI.parse(url)
15
+
16
+ information = information.merge('provision_status' => status.downcase)
17
+ $evm.log('info', "send_order_status: Information: #{information}")
18
+ json = {
19
+ status: "#{status}",
20
+ message: "#{message}",
21
+ info: information
22
+ }
23
+ $evm.log('info', "send_order_status: Information #{json}")
24
+ begin
25
+ http = Net::HTTP.new(uri.host, uri.port)
26
+ request = Net::HTTP::Put.new(uri.path)
27
+ request.content_type = 'application/json'
28
+ request.body = json.to_json
29
+ response = http.request(request)
30
+ $evm.log('info', "send_order_status: HTTP Response code: #{response.code}")
31
+ $evm.log('info', "send_order_status: HTTP Response message: #{response.message}")
32
+ rescue StandardError => e
33
+ $evm.log('error', "send_order_status: Exception caught while sending response back to core: #{e.message}")
34
+ end
35
+ end # End of function
36
+
37
+ # Retrieve properties from request
38
+ # MIQ makes product_details into a string.
39
+ # Must make into a hash
40
+ product_details = $evm.root['dialog_order_item']
41
+ order_item_hash = JSON.parse(product_details.gsub("'", '"').gsub('=>', ':'))
42
+ product_hash = order_item_hash['product_details']
43
+ order_id = order_item_hash['id']
44
+ uuid = order_item_hash['uuid']
45
+ db_instance_id = product_hash['instance_name']
46
+ snapshot_identifier = product_hash['snapshot_identifier']
47
+ final_snapshot = Integer(product_hash['final_snapshot'])
48
+ access_key = product_hash['access_key_id']
49
+ secret_access_key = product_hash['secret_access_key']
50
+ host = $evm.root['dialog_referer']
51
+ headers = [$evm.root['dialog_email'], $evm.root['dialog_token']]
52
+
53
+ $evm.log('info', "RDSRetire: snapshot identifier #{snapshot_identifier}")
54
+ $evm.log('info', "RDSRetire: final snapshot #{final_snapshot}")
55
+ $evm.log('info', "RDSRetire: DB_Instance_ID: #{db_instance_id}")
56
+
57
+ $evm.log('info', 'RDSRetire: Enter retirement method.')
58
+ rds = AWS::RDS.new(
59
+ access_key_id: access_key,
60
+ secret_access_key: secret_access_key
61
+ )
62
+
63
+ # Obtain the selected instance from AWS
64
+ instance_collection = rds.db_instances
65
+ instance = instance_collection[db_instance_id]
66
+
67
+ info = {
68
+ 'id' => order_id,
69
+ 'uuid' => uuid
70
+ }
71
+
72
+ # Delete the instance
73
+ if instance.exists?
74
+ $evm.log('info', 'RDSRetire: Instance exists. Begin retirement.')
75
+ if final_snapshot == 0
76
+ begin
77
+ instance.delete(
78
+ skip_final_snapshot: true
79
+ )
80
+ rescue AWS::RDS::Errors::InvalidDBInstanceState => e
81
+ $evm.log('error', "RDSRetire: Invalid Instance state: #{e.message}")
82
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
83
+ exit
84
+ rescue AWS::RDS::Errors => e
85
+ $evm.log('error', "RDSRetire: Exception caught when deleting instance: #{e.message}")
86
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
87
+ exit
88
+ end
89
+ elsif final_snapshot == 1
90
+ begin
91
+ instance.delete(
92
+ skip_final_snapshot: false,
93
+ final_db_snapshot_identifier: snapshot_identifier
94
+ )
95
+ rescue AWS::RDS::Errors::InvalidDBInstanceState => e
96
+ $evm.log('error', "RDSRetire: Invalid Instance state: #{e.message}")
97
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
98
+ exit
99
+ rescue AWS::RDS::Errors => e
100
+ $evm.log('error', "RDSRetire: Exception caught when deleting instance: #{e.message}")
101
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
102
+ exit
103
+ end
104
+ else
105
+ $evm.log('error', 'RDSRetire: Must specify final snapshot value.')
106
+ send_order_status(host, headers, 'CRITICAL', order_id, info, 'Must specify final snapshot value')
107
+ end
108
+ while instance.exists? && instance.status == 'deleting'
109
+ $evm.log('info', 'RDSRetire: Instance is deleting.')
110
+ sleep 5
111
+ end
112
+ $evm.log('info', 'RDSRetire: Instance deletion complete. Begin payload response.')
113
+ send_order_status(host, headers, 'OK', order_id, info, 'Instance retired.')
114
+ else
115
+ $evm.log('error', "RDSRetire: Instance #{db_instance_id} does not exist.")
116
+ send_order_status(host, headers, 'CRITICAL', order_id, info, 'Instance does not exist')
117
+ end
@@ -0,0 +1,93 @@
1
+ # Description: This MIQ Method destroys an S3 instance
2
+ # Based off of the criteria selected in the marketplace
3
+
4
+ # For use in MIQ under the
5
+ # For use in Service/Provisioning/StateMachines/Methods/RetireS3
6
+
7
+ require 'aws-sdk'
8
+ require 'uri/http'
9
+ require 'json'
10
+
11
+ def send_order_status(referer, headers, status, order_id, information, message = '')
12
+ path = "/order_items/#{order_id}/provision_update"
13
+ host = URI.parse(referer).host
14
+ url = "http://#{host}#{path}"
15
+ uri = URI.parse(url)
16
+
17
+ information = information.merge('provision_status' => status.downcase)
18
+ $evm.log('info', "send_order_status: Information: #{information}")
19
+ json = {
20
+ status: "#{status}",
21
+ message: "#{message}",
22
+ info: information
23
+ }
24
+ $evm.log('info', "send_order_status: Information #{json}")
25
+ begin
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ request = Net::HTTP::Put.new(uri.path)
28
+ request.content_type = 'application/json'
29
+ request.body = json.to_json
30
+ response = http.request(request)
31
+ $evm.log('info', "send_order_status: HTTP Response code: #{response.code}")
32
+ $evm.log('info', "send_order_status: HTTP Response message: #{response.message}")
33
+ rescue StandardError => e
34
+ $evm.log('error', "send_order_status: Exception caught while sending response back to core: #{e.message}")
35
+ end
36
+ end # End of function
37
+
38
+ $evm.log('info', 'RetireS3: Enter Method.')
39
+
40
+ # Retrieve properties from request
41
+ # MIQ makes product_details into a string.
42
+ # Must make into a hash
43
+ product_details = $evm.root['dialog_order_item']
44
+ order_item_hash = JSON.parse(product_details.gsub("'", '"').gsub('=>', ':'))
45
+ product_hash = order_item_hash['product_details']
46
+ order_id = order_item_hash['id']
47
+ uuid = order_item_hash['uuid']
48
+ access_key = product_hash['access_key_id']
49
+ secret_access_key = product_hash['secret_access_key']
50
+ bucket_name = product_hash['instance_name']
51
+ host = $evm.root['dialog_referer']
52
+ headers = [$evm.root['dialog_email'], $evm.root['dialog_token']]
53
+
54
+ S3 = AWS::S3.new(
55
+ access_key_id: access_key,
56
+ secret_access_key: secret_access_key
57
+ )
58
+
59
+ $evm.log('info', 'RetireS3: Bucket name: #{bucket_name}')
60
+ begin
61
+ info = {
62
+ 'id' => order_id,
63
+ 'uuid' => uuid
64
+ }
65
+ bucket = S3.buckets[bucket_name]
66
+ if bucket.exists?
67
+ bucket.delete
68
+ else
69
+ $evm.log('error', 'Retire S3: Bucket does not exist. ')
70
+ send_order_status(host, headers, 'CRITICAL', order_id, info, 'Bucket does not exist and cannot be deleted')
71
+ exit
72
+ end
73
+ rescue AWS::S3::Errors::InvalidClientTokenId => e
74
+ $evm.log('error', "RetireS3: Invalid client token exception caught: #{e.message}.")
75
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
76
+ exit
77
+ rescue AWS::S3::Errors::InvalidParameterValue => e
78
+ $evm.log('error', "RetireS3: Invalid parameter exception caught: #{e.message}")
79
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
80
+ exit
81
+ rescue AWS::S3::Errors => e
82
+ $evm.log('error', "RetireS3: AWS S3 exception caught: #{e.message}")
83
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
84
+ exit
85
+ rescue StandardError => e
86
+ $evm.log('error', "RetireS3: General exception caught: #{e.message}")
87
+ $evm.log('error', "RetireS3: General exception backtrace: #{e.message}")
88
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
89
+ exit
90
+ end
91
+
92
+ $evm.log('info', 'RetireS3: Bucket deleted successfully.')
93
+ send_order_status(host, headers, 'OK', order_id, info, 'Instance retired.')
@@ -0,0 +1,98 @@
1
+ # Description: This MIQ Method un-verifies e-mail addresses
2
+ # From an existing SES service
3
+
4
+ # For use in MIQ under the
5
+ # /Provisioning/StateMachines/Methods/CreateSES
6
+
7
+ require 'aws-sdk'
8
+ require 'net/http'
9
+ require 'uri/http'
10
+ require 'json'
11
+
12
+ $evm.log('info', 'RetireSES: Entering method')
13
+
14
+ def send_order_status(referer, headers, status, order_id, information, message = '')
15
+ path = "/order_items/#{order_id}/provision_update"
16
+ host = URI.parse(referer).host
17
+ url = "http://#{host}#{path}"
18
+ uri = URI.parse(url)
19
+
20
+ information = information.merge('provision_status' => status.downcase)
21
+ $evm.log('info', "send_order_status: Information: #{information}")
22
+ json = {
23
+ status: "#{status}",
24
+ message: "#{message}",
25
+ info: information
26
+ }
27
+ $evm.log('info', "send_order_status: Information #{json}")
28
+ begin
29
+ http = Net::HTTP.new(uri.host, uri.port)
30
+ request = Net::HTTP::Put.new(uri.path)
31
+ request.content_type = 'application/json'
32
+ request.body = json.to_json
33
+ response = http.request(request)
34
+ $evm.log('info', "send_order_status: HTTP Response code: #{response.code}")
35
+ $evm.log('info', "send_order_status: HTTP Response message: #{response.message}")
36
+ rescue StandardError => e
37
+ $evm.log('error', "send_order_status: Exception caught while sending response back to core: #{e.message}")
38
+ end
39
+ end # End of function
40
+
41
+ # Retrieve dialog properties
42
+ # Retrieve properties from request
43
+ # MIQ makes product_details into a string.
44
+ # Must make into a hash
45
+ product_details = $evm.root['dialog_order_item']
46
+ order_item_hash = JSON.parse(product_details.gsub("'", '"').gsub('=>', ':'))
47
+ product_hash = order_item_hash['product_details']
48
+ order_id = order_item_hash['id']
49
+ uuid = order_item_hash['uuid']
50
+ access_key = product_hash['access_key_id']
51
+ secret_access_key = product_hash['secret_access_key']
52
+ email = product_hash['email']
53
+ host = $evm.root['dialog_referer']
54
+ headers = [$evm.root['dialog_email'], $evm.root['dialog_token']]
55
+
56
+ AWS.config(
57
+ access_key_id: access_key,
58
+ secret_access_key: secret_access_key
59
+ )
60
+
61
+ $evm.log('info', 'RetireSES: create service')
62
+
63
+ info = {
64
+ 'id' => order_id,
65
+ 'uuid' => uuid
66
+ }
67
+
68
+ ses = AWS::SimpleEmailService.new
69
+
70
+ # Setup a verified sender if a sender was chosen
71
+ if email != ''
72
+ begin
73
+ email_identities = email.split(',')
74
+ email_identities.each do |e|
75
+ $evm.log('info', "RetireSES: E-mail Identity: #{e}")
76
+ ses.identities[e].delete
77
+ $evm.log('info', 'RetireSES: Email Identity removed.')
78
+ end
79
+ rescue AWS::SimpleEmailService::Errors::InvalidClientTokenId => e
80
+ $evm.log('error', "RetireSES: Exception caught when creating instance: #{e.message}")
81
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
82
+ exit
83
+ rescue AWS::SimpleEmailService::Errors::InvalidParameterValue => e
84
+ $evm.log('error', "RetireSES: Invalid parameter exception caught: #{e.message}")
85
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
86
+ exit
87
+ rescue AWS::SimpleEmailService::Errors => e
88
+ $evm.log('error', "RetireSES: Exception caught: #{e.message}")
89
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
90
+ exit
91
+ rescue StandardError => e
92
+ $evm.log('error', "RetireSES: Exception caught #{e.message}")
93
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "#{e.message}")
94
+ exit
95
+ end
96
+ end
97
+
98
+ send_order_status(host, headers, 'OK', order_id, info, 'Instance retired.')
@@ -0,0 +1,70 @@
1
+ # This method will delete a specified VM
2
+
3
+ require 'rbvmomi'
4
+ require 'net/http'
5
+ require 'uri/http'
6
+ require 'json'
7
+
8
+ def send_order_status(host, headers, status, order_id, information, message = '')
9
+ path = "/order_items/#{order_id}/provision_update"
10
+ url = "http://#{host}#{path}"
11
+ uri = URI.parse(url)
12
+
13
+ information = information.merge('provision_status' => status.downcase)
14
+ $evm.log('info', "send_order_status: Information: #{information}")
15
+ json = {
16
+ status: "#{status}",
17
+ message: "#{message}",
18
+ info: information
19
+ }
20
+ $evm.log('info', "send_order_status: Information #{json}")
21
+ begin
22
+ http = Net::HTTP.new(uri.host, uri.port)
23
+ request = Net::HTTP::Put.new(uri.path)
24
+ request.content_type = 'application/json'
25
+ request.body = json.to_json
26
+ response = http.request(request)
27
+ $evm.log('info', "send_order_status: HTTP Response code: #{response.code}")
28
+ $evm.log('info', "send_order_status: HTTP Response message: #{response.message}")
29
+ rescue HTTPExceptions => e
30
+ $evm.log('error', "send_order_status: HTTP Exception caught while sending response back to core: #{e.message}")
31
+ rescue StandardError => e
32
+ $evm.log('error', "send_order_status: Exception caught while sending response back to core: #{e.message}")
33
+ end
34
+ end # End of function
35
+
36
+ # Retrieve all information set from the marketplace
37
+ product_details = $evm.root['dialog_product_details']
38
+ $evm.log('info', "CreateVMWareVM: Product Details: #{product_details}")
39
+ product_hash = JSON.parse(product_details.gsub("'", '"').gsub('=>', ':'))
40
+ datacenter = product_hash['datacenter']
41
+ host = product_hash['host']
42
+ port = Integer(product_hash['port']) unless product_hash['port'].nil || product_hash[port] == ''
43
+ user = product_hash['user']
44
+ password = product_hash['password']
45
+ uuid = product_hash['uuid']
46
+ order_id = product_hash['id']
47
+ instance_name = product_hash['instance_name']
48
+ headers = [$evm.root['dialog_email'], $evm.root['dialog_token']]
49
+ info = {
50
+ 'id' => order_id,
51
+ 'uuid' => uuid
52
+ }
53
+
54
+ begin
55
+ $evm.log('info', 'DeleteVMWareVM: Begin')
56
+ vim = RbVmomi::VIM.connect host: host, port: port, user: user, password: password, insecure: false
57
+ dc = vim.serviceInstance.find_datacenter(datacenter)
58
+ $evm.log('info', 'DeleteVMWareVM: Found datacenter')
59
+ vm = dc.find_vm(instance_name)
60
+ if vm.nil?
61
+ send_order_status(host, headers, 'CRITICAL', order_id, info, 'Could not find VM')
62
+ exit
63
+ end
64
+ $evm.log('info', 'DeleteVMWareVM: Found VM')
65
+ vm.Destroy_Task(this: vm)
66
+ rescue StandardError => e
67
+ send_order_status(host, headers, 'CRITICAL', order_id, info, "Exception caught while creating VM: #{e.message}")
68
+ $evm.log('error', "DeleteVMWareVM: Error while deleting VM: #{e.message}")
69
+ exit
70
+ end
@@ -0,0 +1,364 @@
1
+ #
2
+ # Description: This miq method will update chef and send back information to servicemix
3
+ #
4
+ require 'json'
5
+ require 'aws-sdk'
6
+ require 'chef'
7
+ require 'chef/config'
8
+ require 'chef/log'
9
+ require 'chef/rest'
10
+ require 'chef/http'
11
+ require 'chef/node'
12
+ require 'rest-client' # must be after chef/rest
13
+ require 'erb'
14
+
15
+ # =================================
16
+ # miq connector module
17
+ # =================================
18
+ module MiqConnector
19
+
20
+ class ServicemixPayload
21
+ attr_accessor :data, :template
22
+
23
+ def initialize(data)
24
+ # if we want to specify the template in an external file we could get it this way
25
+ # vs declaring it inline.
26
+ #@template = File.read(template)
27
+
28
+ # We aren't sending the engine tags as of 2014-09-18
29
+ # "tags": [ <%= item[:tags].map{|i| '"' + i + '"'}.join(',') %> ],
30
+
31
+ # status should be one of the following: OK, WARNING, CRITICAL, UNKNOWN
32
+ @template = %{
33
+ {
34
+ "status": "#{data[:status]}",
35
+ "description": "#{data[:description]}",
36
+ "order_id":"#{data[:order_id]}",
37
+ "items": [
38
+ <% data[:items].each_with_index do |item, index| %>
39
+ {
40
+ "order_product_id":"#{data[:order_product_id]}",
41
+ "mpuuid": "<%= item[:mpuuid] %>",
42
+ "public_fqdn": "<%=item[:fqdn] %>",
43
+ "cloudforms_guid": "<%= item[:cloudforms_guid] %>",
44
+ "public_ip_addr": "<%= item[:public_ip_address] %>",
45
+ "aws_instance_id": "<%= item[:aws_instance_id] %>",
46
+ "private_fqdn": "<%= item[:private_fqdn] %>",
47
+ "private_ip_addr": "<%= item[:private_ip_address] %>",
48
+ "status": "<%= item[:status] %>",
49
+ "vmid": "<%= item[:vmid] %>"
50
+ }<% if index+1 != data[:items].length %>,<% end %>
51
+ <% end %>
52
+ ]
53
+ }
54
+ }
55
+ @data = data
56
+ end
57
+
58
+ def json()
59
+ b = binding
60
+ template = ERB.new(@template, 0, "%<>")
61
+ return template.result(b)
62
+ end
63
+
64
+ end
65
+
66
+ class MiqConnector
67
+ attr_accessor :aws_instance_data, :miq_request_data
68
+
69
+ def log(msg)
70
+ #@logger_file.puts(msg)
71
+ $evm.log("info", msg)
72
+ end
73
+
74
+ def initialize(miq_request_data)
75
+ @miq_request_data = miq_request_data
76
+ #@logger_file = File.open('/home/miqbuilder/miq_connector.log', 'a')
77
+
78
+ raise "Unexpected/Incomplete configuration" if !self.is_configured?
79
+ # extract the vm ids
80
+ aws_vm_ids = @miq_request_data[:aws_vms].map {|vm| vm.uid_ems}
81
+ log("Loading AWS data ....")
82
+ @aws_instance_data = load_amazon_instance_collection_info(aws_vm_ids)
83
+ log("AWS data loaded")
84
+ log("== AWS data ===============")
85
+ log(@aws_instance_data.inspect)
86
+ log("== END AWS data ===============")
87
+ end
88
+
89
+ def process_order
90
+ # json template for servicemix
91
+ data = {}
92
+ data[:status] = "completed"
93
+ data[:description] = "Order Provisioned Successfully"
94
+ data[:order_product_id] = @miq_request_data[:order_product_id]
95
+ data[:order_id] = @miq_request_data[:order_id]
96
+ items = [] # this should only be one item
97
+
98
+ if @aws_instance_data.data.has_key?(:instances_set)
99
+ puts "has 'instances_set'"
100
+ instances = @aws_instance_data.data[:instances_set]
101
+ else
102
+ instances = @aws_instance_data.data[:instance_index]
103
+ end
104
+
105
+ # this should only be a single instance
106
+ instances.each do |aws_i|
107
+ aws_instance = aws_i[1]
108
+ # find the aws vm object that matches the current aws instance
109
+ miq_vm = @miq_request_data[:aws_vms].find{|e| e.uid_ems == aws_instance[:instance_id]}
110
+
111
+ # must be done in the loop because we have to update each chef server indvidually
112
+ update_chef(aws_instance[:private_ip_address], @miq_request_data[:chef_roles])
113
+
114
+ # build the item array of hashes for servicemix
115
+ item = {
116
+ :order_product_id => @miq_request_data[:order_product_id],
117
+ :mpuuid => @miq_request_data[:mpuuid],
118
+ :public_fqdn => aws_instance[:dns_name],
119
+ :cloudforms_guid => miq_vm.guid,
120
+ :public_ip_address => aws_instance[:ip_address],
121
+ :aws_instance_id => aws_instance[:instance_id],
122
+ :private_fqdn => aws_instance[:private_dns_name],
123
+ :private_ip_address => aws_instance[:private_ip_address],
124
+ :chef_roles => @miq_request_data[:chef_roles],
125
+ :ip_addr => aws_instance[:ip_address],
126
+ :vmid => miq_vm.id,
127
+ :status => "completed"
128
+
129
+ }
130
+
131
+ # add the item to items array for this order
132
+ items.push item
133
+ end
134
+
135
+
136
+ data[:items] = items
137
+
138
+ # inject the data into the template
139
+ servicemix_payload = ServicemixPayload.new(data)
140
+ servicemix_data = servicemix_payload.json()
141
+
142
+ # send the data off to servicemix with all of the instance data
143
+ log(servicemix_data.to_json)
144
+ update_servicemix(servicemix_data)
145
+ end
146
+
147
+ def is_configured?
148
+ if (is_chef_configured? && is_servicemix_configured? && is_amazon_configured?)
149
+ return true
150
+ else
151
+ return false
152
+ end
153
+ end
154
+
155
+ def is_chef_configured?
156
+ if !@miq_request_data[:chef_server_url].nil? && !@miq_request_data[:chef_client_name].nil? && !@miq_request_data[:chef_signing_key_filename].nil?
157
+ # TODO test to see that pem file is accessible
158
+ return true
159
+ else
160
+ return false
161
+ end
162
+ end
163
+
164
+ def is_servicemix_configured?
165
+ if !@miq_request_data[:servicemix_url].nil?
166
+ return true
167
+ else
168
+ return false
169
+ end
170
+ end
171
+
172
+ # this should probably be more generic for any cloud provider configuration
173
+ def is_amazon_configured?
174
+ if !@miq_request_data[:aws_access_key_id].nil? && !@miq_request_data[:aws_secret_access_key].nil?
175
+ return true
176
+ else
177
+ return false
178
+ end
179
+ end
180
+
181
+ def chef_node_name(private_ip_address)
182
+ chef_name = "ip-#{private_ip_address.gsub('.','-')}"
183
+ return chef_name
184
+ end
185
+
186
+ def load_amazon_instance_collection_info(instance_ids)
187
+ ec2_client = AWS::EC2::Client.new(
188
+ :access_key_id => @miq_request_data[:aws_access_key_id],
189
+ :secret_access_key => @miq_request_data[:aws_secret_access_key]
190
+ )
191
+ log("== EC2 Client created")
192
+ return ec2_client.describe_instances(:instance_ids => instance_ids)
193
+ end
194
+
195
+ def update_chef(private_ip, roles)
196
+ begin
197
+ rest = Chef::REST.new(@miq_request_data[:chef_server_url], @miq_request_data[:chef_client_name], @miq_request_data[:chef_signing_key_filename])
198
+ resource = "nodes/#{chef_node_name(private_ip)}"
199
+ log("== Chef Node Name")
200
+ log(resource)
201
+ log("== End Chef Node Name")
202
+
203
+ log("== Chef Roles ============================")
204
+ log(roles.inspect)
205
+ log("Roles is a: #{roles.class}")
206
+ log("== End Chef Roles ============================")
207
+
208
+ chef_node = rest.get_rest(resource)
209
+
210
+ log("== Chef Data Fetched ============================")
211
+ log(chef_node.to_json)
212
+ log("== End Chef Data Fetched============================")
213
+
214
+ #reformat the role list to use the format "role[rolname]"
215
+ roles.map {|r| "role[#{r}]"}
216
+
217
+ # set the roles
218
+ chef_node.run_list(roles)
219
+
220
+ log("== Updated Chef Data ============================")
221
+ log(chef_node.to_json)
222
+ log("== End Updated Chef Data ============================")
223
+
224
+
225
+ # update this chef node with the roles
226
+ rest.put(resource, chef_node)
227
+
228
+ updated_node = rest.get(resource)
229
+
230
+ log("== Retrieved Chef Data ============================")
231
+ log(updated_node.to_json)
232
+ log("== End Retrieved Chef Data ============================")
233
+ log("== Chef successfully updated")
234
+
235
+ return chef_node.to_json
236
+ rescue => err
237
+ failed_msg = %{
238
+ {
239
+ "status": "WARNING",
240
+ "description": "There was a problem updating chef.",
241
+ "order_id":"#{@miq_request_data[:order_id]}",
242
+ "items": [{
243
+ "order_product_id": "#{@miq_request_data[:order_product_id]}",
244
+ "mpuuid": "none",
245
+ "public_fqdn": "none",
246
+ "cloudforms_guid": "none",
247
+ "public_ip_addr": "none",
248
+ "aws_instance_id": "none",
249
+ "private_fqdn": "",
250
+ "private_ip_addr": "",
251
+ "status": "failed",
252
+ "vmid": "none"
253
+ }]
254
+ }
255
+ }
256
+
257
+ update_servicemix(failed_msg)
258
+ log(err.message)
259
+ log(err.backtrace.inspect)
260
+ end
261
+ end
262
+
263
+ def update_servicemix(json_to_post)
264
+ begin
265
+ resp = RestClient.post(@miq_request_data[:servicemix_url], json_to_post, :content_type => :json){|response, request, result, &block|
266
+ log("== Data sent to servicemix ============================")
267
+ log(json_to_post)
268
+ log("== End Data sent to servicemix ============================")
269
+ case response.code
270
+
271
+ when 200
272
+ log("servicemix returned code 200 and updated successfully")
273
+ else
274
+ log("servicemix returned code #{response.code}")
275
+ end
276
+
277
+ }
278
+ rescue => e
279
+ log("== Problem sending data to servicemix")
280
+ end
281
+ end
282
+
283
+ end
284
+ end
285
+
286
+ # =================================
287
+ # end miq connector module
288
+ # =================================
289
+
290
+ begin
291
+
292
+ @method = '======= Update servicemix and Chef =========='
293
+ @debug = true
294
+
295
+ $evm.log("info", "#{@method}")
296
+
297
+ if ($evm.root['dialog_chef_roles'].nil?)
298
+ chef_roles = ['boozallen']
299
+ else
300
+ # extract the chef roles from the json
301
+ chef_roles = JSON.parse($evm.root['dialog_chef_roles'])
302
+ # make sure that the roles include "boozallen"
303
+ chef_roles.unshift('boozallen')
304
+ end
305
+
306
+ # build the data that the miq connector class need to be instantiated
307
+ miq_request_data = {
308
+ :chef_server_url => $evm.root['dialog_chef_url'],
309
+ :chef_client_name => $evm.root['dialog_chef_client_name'],
310
+ :chef_signing_key_filename => $evm.root['dialog_chef_signing_key_filename'],
311
+ :servicemix_url => $evm.root['dialog_servicemix_url'],
312
+ :order_id => $evm.root['dialog_order_id'],
313
+ :order_product_id => $evm.root['dialog_order_product_id'],
314
+ :aws_access_key_id => $evm.root['dialog_aws_access_id'],
315
+ :aws_secret_access_key => $evm.root['dialog_aws_secret_access_key'],
316
+ :aws_vms => $evm.root['service_template_provision_task'].destination.vms,
317
+ :chef_roles => chef_roles,
318
+ :mpuuid => $evm.root['dialog_mpuuid']
319
+ }
320
+
321
+ # Get current provisioning status
322
+ task = $evm.root['service_template_provision_task']
323
+ task_status = task['status']
324
+
325
+ $evm.log("info", "Task Status==#{task_status}")
326
+ dpi = MiqConnector::MiqConnector.new(miq_request_data)
327
+ $evm.log("info", "dpi object instantiated successfully")
328
+
329
+ # if the order wasn't provisioned return
330
+ if task.status != 'ok'
331
+ $evm.log("warn", "Provision Failed for order: #{$evm.root['dialog_order_id']}, order_product_id:#{$evm.root['dialog_order_product_id']}")
332
+ failed_msg = %{
333
+ {
334
+ "status": "failed",
335
+ "description": "The order has failed",
336
+ "order_id":"#{$evm.root['dialog_order_id']}",
337
+ "items": [{
338
+ "order_product_id": "#{@miq_request_data[:order_product_id]}",
339
+ "mpuuid": "none",
340
+ "public_fqdn": "none",
341
+ "cloudforms_guid": "none",
342
+ "public_ip_addr": "none",
343
+ "aws_instance_id": "none",
344
+ "private_fqdn": "",
345
+ "private_ip_addr": "",
346
+ "status": "failed",
347
+ "vmid": "none"
348
+ }]
349
+ }
350
+ }
351
+ dpi.update_servicemix(failed_msg)
352
+ else
353
+ dpi.process_order()
354
+ end
355
+ $evm.log("info", "servicemix and Chef updated successfully.")
356
+
357
+
358
+
359
+ exit MIQ_OK
360
+
361
+ rescue => err
362
+ $evm.log("error", "#{@method} - [#{err}]\n#{err.backtrace.join("\n")}")
363
+ exit MIQ_STOP
364
+ end