avst-cloud 0.1.35 → 0.1.40

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 08b2bde0582221a0d81aae6d0b3606206633d23ebffb3350273b6e94118ae05c
4
- data.tar.gz: 95b4457c08517ea0ea4275cc866262eb8067de3bc9ff93fe0e12837ceb7fadfe
3
+ metadata.gz: 46cf2e686b412006cb9a4cbd2ae7fb624f5dbadf800bc05db414e7b2718e98e0
4
+ data.tar.gz: b56b12c41540f2d787fb80db59cc9cc6d1017721b327fa9bfd48adb0bab75afa
5
5
  SHA512:
6
- metadata.gz: 7d1253877fe6464c5c7c9a8a8d6a3649c73cd8f5cf9a0c2948269742c7d5c9851c75b11e7c12dcc1535cdd3566ec5344888b47600c7a878417e52dbf8d40bd43
7
- data.tar.gz: a57749823fcb9baffdca0f3ecd504b3329f8acc2dd92370ff1241b7c36767df345f12800140311f7bb4b07c71134dc994c539140aaf0206cbf81e13cdc4b3ed2
6
+ metadata.gz: 25461b2620b01cfd5e82909a00ad833787df06ef96729ce76e476cfddc9eb83189add2a324c2c7b51fb5c5e3d8428fd19e0d9520315ea76f868b23966c40b6cf
7
+ data.tar.gz: 388417ecbce19754583fb90c0b3e884e4d1d8ef1b585d8feef8b1e908dee98e8615914571584a7ce8c61ebfc4e5f58180ea1bd266649802d91d8132e5406072d
data/.travis.yml CHANGED
@@ -1,4 +1,8 @@
1
1
  language: ruby
2
+ before_install:
3
+ # https://github.com/travis-ci/travis-rubies/issues/57#issuecomment-458981237
4
+ - "find /home/travis/.rvm/rubies -wholename '*default/bundler-*.gemspec' -delete"
5
+ - gem install bundler --version 1.17.3
2
6
  notifications:
3
7
  email: false
4
8
  hipchat:
data/avst-cloud.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "avst-cloud"
7
- spec.version = '0.1.35'
7
+ spec.version = '0.1.40'
8
8
  spec.authors = ["Martin Brehovsky", "Jon Bevan", "Matthew Hope"]
9
9
  spec.email = ["mbrehovsky@adaptavist.com", "jbevan@adaptavist.com", "mhope@adaptavist.com"]
10
10
  spec.summary = %q{Automated creation, bootstrapping and provisioning of servers }
@@ -15,13 +15,14 @@ Gem::Specification.new do |spec|
15
15
  spec.executables = ["avst-cloud", "avst-cloud-puppet", "avst-cloud-rackspace", "avst-cloud-azure", "avst-cloud-azure-rm"]
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
- spec.add_development_dependency "bundler", "~> 1.16.1"
18
+ spec.add_development_dependency "bundler", "~> 1.17.3"
19
19
  spec.add_development_dependency "rake"
20
20
  spec.add_dependency "fog"
21
21
  spec.add_dependency "fog-core", "1.43.0"
22
- spec.add_dependency "fog-azure"
23
- spec.add_dependency "fog-azure-rm", "0.0.3"
24
- spec.add_dependency "azure"
22
+ ###spec.add_dependency "fog-azure"
23
+ ###spec.add_dependency "fog-azure-rm", "0.0.3"
24
+ spec.add_dependency "fog-google", "1.8.2"
25
+ ###spec.add_dependency "azure"
25
26
  spec.add_dependency "rvm-capistrano"
26
27
  spec.add_dependency "capistrano", "3.4.1"
27
28
  spec.add_dependency "capistrano-rvm"
@@ -30,6 +31,8 @@ Gem::Specification.new do |spec|
30
31
  spec.add_dependency "derelict"
31
32
  spec.add_dependency "docopt", ">= 0.5.0"
32
33
  spec.add_dependency "rainbow", '3.0.0'
33
- spec.add_dependency "nokogiri", '1.8.2'
34
+ spec.add_dependency "nokogiri", "~> 1.8.5"
35
+ spec.add_dependency "signet", "0.14.1"
34
36
  end
35
37
 
38
+
@@ -39,7 +39,7 @@ platform = nil # defaults to Linux
39
39
  server_name = "hostname1"
40
40
  user = "ubuntu"
41
41
  # Must comply to Azure pass guidelines
42
- password = "superSecretUbuntuPass111_@"
42
+ password = ""
43
43
  location = nil # Will default to West Europe
44
44
  resource_group = "new_resource_group" # if RG does not exists it will create it
45
45
  vm_size = nil # Defaults to Basic_A0
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright 2015 Adaptavist.com Ltd.
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
+ require 'avst-cloud'
18
+ require 'avst-cloud/gcp_connection'
19
+ require 'avst-cloud/gcp_server'
20
+
21
+ avst_cloud_base="#{File.expand_path("../../", __FILE__)}"
22
+
23
+ # FILL IN YOUR GCP ACCOUNT DETAILS (Access Key ID and Secret Access Key), GIT REPO AND MAKE SURE
24
+ # FILES IN files FOLDER HAS CORRECT CONTENT
25
+ provider_user=''
26
+ provider_pass=''
27
+ project=''
28
+ region='europe-west1'
29
+
30
+ # Initiate connector object
31
+ conn = AvstCloud::GcpConnection.new(provider_user, provider_pass, region, project)
32
+
33
+ server_name = 'hostname1'
34
+
35
+ flavour = nil # defaults to t2.micro
36
+ hdd_device_path = nil # defaults to '/dev/sda1'
37
+ machine_type_id = nil
38
+ os = "centos-7"
39
+
40
+ key_name = 'admin' # key name, e.g. admin
41
+ ssh_public_key = "path/to/your/admin.pem.pub" # Full path to ssh public key, e.g. /tmp/admin.pem.pub
42
+ ssh_private_key = "path/to/your/admin.pem" # Full path to ssh private key, e.g. /tmp/admin.pem
43
+ subnet_id = nil # Your subnet
44
+ security_group_ids = [''] # List of security groups
45
+ root_disk_size = nil # In GB
46
+ additional_hdds = {}
47
+ vpc = nil
48
+ created_by = nil
49
+ root_username = nil
50
+ custom_tags = []
51
+ availability_zone = 'europe-west1-b'
52
+ delete_root_disk = true
53
+
54
+ # display server status
55
+ ##server_detail = conn.server_status(server_name)
56
+ ##puts server_detail.inspect
57
+ ##conn.list_zones
58
+ ##conn.list_flavours(availability_zone)
59
+ ##conn.list_images
60
+ ##conn.list_networks
61
+ ##conn.list_disk_types(availability_zone)
62
+
63
+ server = conn.create_server(server_name, flavour, os, key_name, ssh_public_key, ssh_private_key, subnet_id, security_group_ids, root_disk_size, machine_type_id, availability_zone, additional_hdds, vpc, created_by, custom_tags, root_username, delete_root_disk)
64
+
65
+ # server = conn.server(server_name, root_username, ssh_private_key, os)
66
+ # server.destroy
67
+
68
+ # puts conn.server_status(server_name)
69
+ # exit
70
+
71
+ pre_upload_commands = [
72
+ "echo 'pre_upload_command was here' >> /tmp/pre_upload",
73
+ ]
74
+
75
+ custom_file_uploads = {
76
+ "#{avst_cloud_base}/files/id_rsa" => "/tmp/.",
77
+ "#{avst_cloud_base}/files/known_hosts" => "/tmp/."
78
+ }
79
+
80
+ # Uploading ssh keys to access git repo in provisioning stage, make sure you provide correct keys
81
+ post_upload_commands = [
82
+ "mkdir /home/ubuntu/.ssh",
83
+ "mv /tmp/id_rsa /home/ubuntu/.ssh/.",
84
+ "mv /tmp/known_hosts /home/ubuntu/.ssh/.",
85
+ "chmod 0600 /home/ubuntu/.ssh/known_hosts",
86
+ "chmod 0600 /home/ubuntu/.ssh/id_rsa",
87
+ "mkdir /var/opt/puppet",
88
+ "chown ubuntu /var/opt/puppet",
89
+ "apt-get update && apt-get install -o Dpkg::Options::='--force-confold' -f -y git puppet-common puppet"
90
+ ]
91
+
92
+ remote_server_debug = true
93
+ debug_structured_log = false
94
+
95
+ ##!##server.bootstrap(pre_upload_commands, custom_file_uploads, post_upload_commands, remote_server_debug, debug_structured_log, false)
96
+
97
+ git = "ssh://git@you_repo.git"
98
+ branch = "master"
99
+ reference = nil # Tag
100
+ # In this example we do not use puppet-runner, check doco
101
+ puppet_runner = nil
102
+ puppet_runner_prepare = nil
103
+ avst_cloud_config_dir = nil
104
+ download_dependencies_command = nil
105
+ custom_provisioning_commands = ["echo 'done' >> /tmp/done", "echo 'done' >> /tmp/done1"]
106
+ server_tmp_folder="/tmp/avst_cloud_tmp_#{Time.now.to_i}"
107
+
108
+ destination_folder = nil # defaults to /var/opt/puppet
109
+ ##!##server.provision(git, branch, server_tmp_folder, reference, custom_provisioning_commands, puppet_runner, puppet_runner_prepare, destination_folder, avst_cloud_config_dir, download_dependencies_command)
110
+
111
+ # puts conn.server_status(server_name)
112
+ # server.stop
113
+
114
+ # puts conn.server_status(server_name)
115
+ # server.start
116
+
117
+ # puts conn.server_status(server_name)
118
+
119
+ # custom_commands=nil
120
+ # server_tmp_folder="/tmp/done"
121
+ # server.post_provisioning_cleanup(custom_commands, os, remote_server_debug, server_tmp_folder)
122
+
123
+ # server.destroy
124
+ # puts conn.server_status(server_name)
@@ -33,7 +33,7 @@ module AvstCloud
33
33
  AvstCloud::AwsServer.new(server, server_name, server.public_ip_address, root_user, root_password)
34
34
  end
35
35
 
36
- def create_server(server_name, flavour, os, key_name, ssh_key, subnet_id, security_group_ids, ebs_size, hdd_device_path, ami_image_id, availability_zone, additional_hdds={}, vpc=nil, created_by=nil, custom_tags={}, root_username=nil)
36
+ def create_server(server_name, flavour, os, key_name, ssh_key, subnet_id, security_group_ids, ebs_size, hdd_device_path, ami_image_id, availability_zone, additional_hdds={}, vpc=nil, created_by=nil, custom_tags={}, root_username=nil, create_elastic_ip=false, encrypt_root=false ,root_encryption_key=nil, delete_root_disk=true, root_disk_type='gp2', root_disk_iops=0, private_ip=nil)
37
37
  # Permit named instances from DEFAULT_FLAVOURS
38
38
  flavour = flavour || "t2.micro"
39
39
  os = os || "ubuntu-14"
@@ -87,26 +87,62 @@ module AvstCloud
87
87
  logger.debug "hdd_device_path - #{device_name}"
88
88
  logger.debug "additional_hdds - #{additional_hdds}"
89
89
  logger.debug "vpc - #{vpc}"
90
+ logger.debug "create_elastic_ip - #{create_elastic_ip}"
91
+ logger.debug "custom_private_ip - #{private_ip}"
90
92
 
91
93
  create_ebs_volume = nil
92
94
  if ebs_size
93
95
  # in case of centos ami we need to use /dev/xvda this is ami dependent
94
- create_ebs_volume = [
95
- {
96
- :DeviceName => device_name,
97
- 'Ebs.VolumeType' => 'gp2',
98
- 'Ebs.VolumeSize' => ebs_size,
99
- }
100
- ]
96
+ root_disk = {
97
+ :DeviceName => device_name,
98
+ 'Ebs.VolumeType' => root_disk_type,
99
+ 'Ebs.VolumeSize' => ebs_size,
100
+ }
101
+ # if the root disk is to be encrypted set te "Encrypted" flag to true, if there is an optional KMS Key ID send that,
102
+ # if not set to nil and thereby defalt to the default key for EBS
103
+ if encrypt_root
104
+ root_disk.merge!('Ebs.Encrypted' => true, 'Ebs.KmsKeyId' => root_encryption_key||nil )
105
+ end
106
+
107
+ # if we do not want to delete the root disk with the VM set the flag
108
+ if delete_root_disk == false || delete_root_disk == 'false'
109
+ root_disk.merge!('Ebs.DeleteOnTermination' => false)
110
+ end
111
+
112
+ # if this is a provisioned IOPS disk set the iops value
113
+ if root_disk_type == 'io1'
114
+ root_disk.merge!('Ebs.Iops' => root_disk_iops)
115
+ end
116
+ # add the root disk as the first entry in the array of disks to create/attach
117
+ create_ebs_volume = [ root_disk ]
118
+
101
119
  if additional_hdds and additional_hdds.is_a?(Hash)
102
120
  additional_hdds.each_value do |disk|
103
121
  volume_type = disk['volume_type'] || 'gp2'
104
122
  if disk['device_name'] && disk['ebs_size']
105
- create_ebs_volume << {
123
+ disk_hash = {
106
124
  :DeviceName => disk['device_name'],
107
125
  'Ebs.VolumeType' => volume_type,
108
126
  'Ebs.VolumeSize' => disk['ebs_size']
109
127
  }
128
+ # if the additional disk is to be encrypted set te "Encrypted" flag to true, if there is an optional KMS Key ID send that,
129
+ # if not set to nil and thereby defalt to the default key for EBS
130
+ if disk['encrypted']
131
+ disk_hash.merge!('Ebs.Encrypted' => true, 'Ebs.KmsKeyId' => disk['encryption_key_id'] || nil)
132
+ end
133
+
134
+ # if we do not want to delete the additional disk with the VM set the flag
135
+ if disk['delete_disk_with_vm'] == false || disk['delete_disk_with_vm'] == 'false'
136
+ disk_hash.merge!('Ebs.DeleteOnTermination' => false)
137
+ end
138
+
139
+ # if the additional disk is an provisioned IOPS disk set the iops value
140
+ if volume_type == 'io1'
141
+ disk_hash.merge!('Ebs.Iops' => disk['volume_iops'] || 0)
142
+ end
143
+
144
+ # add this disk to the array of all disks to create/attach
145
+ create_ebs_volume << disk_hash
110
146
  else
111
147
  logger.warn "Failed to create additional hdd, required params device_name (e.g. /dev/sda1) or ebs_size missing: #{disk}"
112
148
  end
@@ -122,6 +158,7 @@ module AvstCloud
122
158
  tags['created_by'] = created_by
123
159
  end
124
160
  tags.merge!(custom_tags)
161
+
125
162
  # create server
126
163
  server = connect.servers.create :tags => tags,
127
164
  :flavor_id => flavour,
@@ -132,8 +169,8 @@ module AvstCloud
132
169
  :security_group_ids => security_group_ids,
133
170
  :availability_zone => availability_zone,
134
171
  :block_device_mapping => create_ebs_volume,
135
- :vpc => vpc
136
-
172
+ :vpc => vpc,
173
+ :private_ip_address => private_ip
137
174
 
138
175
  result_server = AvstCloud::AwsServer.new(server, server_name, nil, root_user, ssh_key)
139
176
  # result_server.logger = logger
@@ -143,6 +180,27 @@ module AvstCloud
143
180
 
144
181
  logger.debug "[DONE]\n\n"
145
182
 
183
+ # create Elastic IP Address if required
184
+ if create_elastic_ip
185
+ logger.debug("Attempting to create elastic IP address")
186
+ elastic_ip = connect.allocate_address("vpc").body
187
+ elastic_ip_address = elastic_ip['publicIp']
188
+ # if we have a server id and an Elastic public IP attempt to join the two togehter
189
+ if server.id and elastic_ip_address
190
+ logger.debug ("Elastic IP #{elastic_ip_address} created, attempting to allocate to server")
191
+ connect.associate_address(server.id, elastic_ip_address)
192
+ # reacquire server object as IP has, probably, changed
193
+ server = find_fog_server(server_name)
194
+
195
+ # create tag on the Elastic IP
196
+ # TODO: add ability for other tags to be defined by the user
197
+ logger.debug("Creating tags on Elastic IP Address #{elastic_ip}\n\n")
198
+ connect.tags.create(:resource_id => elastic_ip['allocationId'], :key => "Name", :value => server_name)
199
+ else
200
+ logger.warn("Elastic IP creation failed, proceeding with non Elastic IP\n\n")
201
+ end
202
+ end
203
+
146
204
  logger.debug "The server has been successfully created, to login onto the server:\n"
147
205
  logger.debug "\t ssh -i #{ssh_key} #{root_user}@#{server.public_ip_address}\n"
148
206
  if create_ebs_volume
@@ -201,6 +259,18 @@ module AvstCloud
201
259
  servers.first
202
260
  end
203
261
 
262
+ def delete_elastic_ip(ip_address)
263
+ address = is_elastic_ip(ip_address)
264
+ if address
265
+ logger.debug "Found Elastic IP #{address.public_ip}, attempting to delete"
266
+ logger.debug "Elastic IP #{ip_address} deleted" if address.destroy
267
+ return true
268
+ else
269
+ logger.debug "IP #{ip_address} does NOT appear to be an Elastic IP"
270
+ end
271
+ return false
272
+ end
273
+
204
274
  private
205
275
  def user_from_os(os)
206
276
  case os.to_s
@@ -233,5 +303,14 @@ module AvstCloud
233
303
  def all_named_servers(server_name)
234
304
  connect.servers.all({'tag:Name' => server_name})
235
305
  end
306
+
307
+ def is_elastic_ip(ip_address)
308
+ connect.addresses.each do |address|
309
+ if address.public_ip == ip_address
310
+ return address
311
+ end
312
+ end
313
+ return false
314
+ end
236
315
  end
237
316
  end
@@ -0,0 +1,310 @@
1
+ # Copyright 2015 Adaptavist.com Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative './cloud_connection.rb'
16
+ require 'fog/google'
17
+ using Rainbow
18
+ module AvstCloud
19
+
20
+ class GcpConnection < AvstCloud::CloudConnection
21
+
22
+ attr_accessor :region
23
+
24
+ def initialize(provider_user, provider_pass, region, project)
25
+ super('Google', provider_user, provider_pass)
26
+ @region = region
27
+ @project = project
28
+ end
29
+
30
+ def server(server_name, root_user, root_password, os=nil)
31
+ server = find_fog_server(server_name)
32
+ if !root_user and os
33
+ root_user = user_from_key(os)
34
+ end
35
+ AvstCloud::GcpServer.new(server, server_name, server.public_ip_address, root_user, root_password)
36
+ end
37
+
38
+ def create_server(server_name, flavour, os, key_name, ssh_public_key, ssh_private_key, subnet_id, security_group_ids, root_disk_size, root_disk_type, machine_type_id, availability_zone, additional_hdds={}, vpc=nil, created_by=nil, custom_tags=[], root_username=nil, delete_root_disk=true)
39
+ flavour = flavour || "g1-small"
40
+ os = os || "centos-7"
41
+ vpc_name = vpc || "default"
42
+ subnet_name = subnet_id || "default"
43
+ machine_type_id = machine_type_id || get_image_name(os)
44
+ if machine_type_id.nil? or machine_type_id.empty?
45
+ machine_type_id = "centos-7-v20190312"
46
+ end
47
+
48
+ unless File.file?(ssh_public_key)
49
+ logger.error "Could not find local public SSH key '#{ssh_public_key}'".red
50
+ raise "Could not find local SSH public key '#{ssh_public_key}'"
51
+ end
52
+
53
+ unless File.file?(ssh_private_key)
54
+ logger.error "Could not find local private SSH key '#{ssh_public_key}'".red
55
+ raise "Could not find local SSH private key '#{ssh_public_key}'"
56
+ end
57
+ root_user = root_username || user_from_key(os)
58
+
59
+ existing_servers = all_named_servers(server_name)
60
+ restartable_servers = existing_servers.select{ |serv| serv.status == 'TERMINATED' }
61
+ #TODO, status is a guess, need to work out if "DELETED" is valid for GCP
62
+ running_servers = existing_servers.select{ |serv| serv.status != 'TERMINATED' && serv.status != 'DELETED' }
63
+
64
+ if running_servers.length > 0
65
+ running_servers.each do |server|
66
+ logger.error "Server #{server_name} with id #{server.id} found in state: #{server.status}".yellow
67
+ end
68
+ raise "Server with the same name found!"
69
+
70
+ elsif restartable_servers.length > 0
71
+ if restartable_servers.length > 1
72
+ running_servers.each do |server|
73
+ logger.error "Server #{server_name} with id #{server.id} found in state: #{server.status}. Can not restart".yellow
74
+ end
75
+ raise "Too many servers can be restarted."
76
+ end
77
+ server = restartable_servers.first
78
+ server.start
79
+ result_server = AvstCloud::GcpServer.new(server, server_name, server.public_ip_address, root_user, ssh_private_key)
80
+ result_server.wait_for_state() {|serv| serv.ready?}
81
+ logger.debug "[DONE]\n\n"
82
+ logger.debug "The server was successfully re-started.\n\n"
83
+ result_server
84
+ else
85
+ logger.debug "Creating GCP server:"
86
+ logger.debug "Server name - #{server_name}"
87
+ logger.debug "Operating system - #{os}"
88
+ logger.debug "image_template_id - #{machine_type_id}"
89
+ logger.debug "flavour - #{flavour}"
90
+ logger.debug "key_name - #{key_name}"
91
+ logger.debug "Public ssh_key - #{ssh_public_key}"
92
+ logger.debug "Private ssh_key - #{ssh_private_key}"
93
+ logger.debug "root user - #{root_user}"
94
+ logger.debug "subnet_id - #{subnet_name}"
95
+ logger.debug "security_group_ids - #{security_group_ids}"
96
+ logger.debug "region - #{@region}"
97
+ logger.debug "availability_zone - #{availability_zone}"
98
+ logger.debug "root_disk_size - #{root_disk_size}"
99
+ logger.debug "additional_hdds - #{additional_hdds}"
100
+ logger.debug "vpc - #{vpc_name}"
101
+
102
+ # Create root disk
103
+ # TODO check if this exists and exit politely, or catch the exception and exit politely
104
+ root_disk_type = root_disk_type || 'pd-standard'
105
+ logger.debug "Creating root disk with type #{root_disk_type}"
106
+ root_disk_url="https://www.googleapis.com/compute/v1/projects/#{@project}/zones/#{availability_zone}/diskTypes/#{root_disk_type}"
107
+ disk = connect.disks.create :name => "#{server_name}-root",
108
+ :size_gb => root_disk_size,
109
+ :zone => availability_zone,
110
+ :source_image => machine_type_id,
111
+ :type => root_disk_url
112
+
113
+ # wait for the disk to be ready
114
+ logger.debug "Waiting for root disk to be ready"
115
+ disk.wait_for { ready? }
116
+
117
+ disk_to_attach=[disk.attached_disk_obj(boot: true, auto_delete: delete_root_disk)]
118
+
119
+ # create additional HDD's if required
120
+ if additional_hdds and additional_hdds.is_a?(Hash)
121
+ disk_count=1
122
+ additional_hdds.each_value do |disk|
123
+ #TODO wortk out how to set disk type!
124
+ if disk['disk_size'] || disk['ebs_size']
125
+ disk_type = disk['disk_type'] || 'pd-standard'
126
+ logger.debug "Creating additional disk #{disk_count} with type #{disk_type}"
127
+ disk_url="https://www.googleapis.com/compute/v1/projects/#{@project}/zones/#{availability_zone}/diskTypes/#{disk_type}"
128
+ delete_disk_with_vm = disk['delete_disk_with_vm'] || false
129
+ additional_disk = connect.disks.create :name => "#{server_name}-disk#{disk_count}",
130
+ :size_gb => disk['disk_size'] || disk['ebs_size'],
131
+ :zone => availability_zone,
132
+ :type => disk_url
133
+ # wait for additional disk
134
+ logger.debug "Waiting for additional disk #{disk_count}"
135
+ additional_disk.wait_for { ready? }
136
+
137
+ # add disk to array of those to be mounted
138
+ disk_to_attach.push additional_disk.attached_disk_obj(boot: false, auto_delete: delete_disk_with_vm)
139
+
140
+ #blank the additional disk object for the next time around
141
+ attached_disk = nil
142
+
143
+ # increment disk counter
144
+ disk_count = disk_count +1
145
+ else
146
+ logger.warn "Failed to create additional hdd, required param disk_size missing: #{disk}"
147
+ end
148
+ end
149
+ end
150
+
151
+ ## GCP tags are not key value pairs
152
+ tags = [server_name, os] + custom_tags
153
+
154
+ # work out the URK for the subnetwork
155
+ subnet_url = "https://www.googleapis.com/compute/v1/projects/#{@project}/regions/#{region}/subnetworks/#{subnet_name}"
156
+
157
+ # create server
158
+ logger.debug "Creating Server"
159
+ server = connect.servers.create :name => server_name,
160
+ :disks => disk_to_attach,
161
+ :machine_type => flavour,
162
+ :private_key_path => ssh_private_key,
163
+ :public_key_path => ssh_public_key,
164
+ :zone => availability_zone,
165
+ :network_interfaces => [{ :network => "global/networks/#{vpc_name}",
166
+ :subnetwork => subnet_url,
167
+ :access_configs => [{
168
+ :name => "External NAT",
169
+ :type => "ONE_TO_ONE_NAT" }]
170
+ }],
171
+ :username => root_user,
172
+ :tags => tags
173
+
174
+ result_server = AvstCloud::GcpServer.new(server, server_name, nil, root_user, ssh_private_key)
175
+ # result_server.logger = logger
176
+ # Check every 5 seconds to see if server is in the active state (ready?).
177
+ # If the server has not been built in 5 minutes (600 seconds) an exception will be raised.
178
+ result_server.wait_for_state() {|serv| serv.ready?}
179
+
180
+ logger.debug "[DONE]\n\n"
181
+ logger.debug "The server has been successfully created, to login onto the server:\n"
182
+ logger.debug "\t ssh -i #{ssh_private_key} #{root_user}@#{server.public_ip_address}\n"
183
+ result_server.ip_address = server.public_ip_address
184
+ result_server
185
+ end
186
+ end
187
+
188
+ def server_status(server_name)
189
+ #TODO, status is a guess, need to work out if this is valid for GCP
190
+ servers = all_named_servers(server_name).select{|serv| serv.status != 'DELETED'}
191
+ if servers.length > 0
192
+ servers.each do |server|
193
+ logger.debug "Server #{server.id} with name '#{server_name}' exists and has state: #{server.status}"
194
+ end
195
+ else
196
+ logger.debug "Server not found for name: #{server_name}"
197
+ end
198
+ end
199
+
200
+ def list_zones
201
+ logger.debug connect.list_zones
202
+ end
203
+
204
+ def list_flavours(zone)
205
+ logger.debug connect.list_machine_types(zone)
206
+ end
207
+
208
+ def list_images
209
+ # Only list current images, not deprecated ones
210
+ get_images.each do |im|
211
+ logger.debug im.inspect
212
+ end
213
+ end
214
+
215
+ def list_networks
216
+ logger.debug connect.list_networks
217
+ end
218
+
219
+ def list_disk_types(availability_zone)
220
+ logger.debug connect.list_disk_types(availability_zone)
221
+ end
222
+
223
+ # Returns list of servers from fog
224
+ def list_known_servers
225
+ connect.servers.all
226
+ end
227
+
228
+ def find_fog_server(server_name, should_fail=true)
229
+ #TODO, status is a guess, need to work out if this is valid for GCP
230
+ servers = all_named_servers(server_name).select{|serv| serv.status != 'DELETED'}
231
+ unless servers.length == 1
232
+ logger.debug "Found #{servers.length} servers for name: #{server_name}".yellow
233
+ if should_fail
234
+ raise "Found #{servers.length} servers for name: #{server_name}"
235
+ end
236
+ end
237
+ servers.first
238
+ end
239
+
240
+ private
241
+ # attempt to workout the user from the key comments! - TODO
242
+ def user_from_key(os)
243
+ raise "Function to extract username from key comment not yet implemented"
244
+ end
245
+ def connect
246
+ unless @connection
247
+ logger.debug "Creating new connection to GCP"
248
+ @connection = Fog::Compute.new({
249
+ :provider => 'Google',
250
+ :google_project => @project,
251
+ :google_client_email => @provider_access_user,
252
+ :google_json_key_location => @provider_access_pass
253
+ })
254
+ end
255
+ @connection
256
+ end
257
+ # get a list of images,
258
+ def get_images(family=nil, deprecated=false)
259
+ # if we are looking to include depreacted images get them all
260
+ if deprecated
261
+ images = connect.images.all
262
+ # if not just get the current ones
263
+ else
264
+ images = connect.images.current
265
+ end
266
+
267
+ # if we are to filter on a list of families do so
268
+ if family
269
+ final_images = Array.new
270
+ images.each do |image|
271
+ if image.family == family
272
+ final_images.push image
273
+ end
274
+ end
275
+ # return the filtered list
276
+ final_images
277
+ # if not just return all results
278
+ else
279
+ # return the results
280
+ images
281
+ end
282
+ end
283
+ # get a single machine image by family
284
+ def get_image_name(family)
285
+ image = get_images(family, false)
286
+ if image.length != 1
287
+ raise "Too many images returned for family #{family}, #{image.length} were returned"
288
+ end
289
+ # return the image name
290
+ image.first.name
291
+
292
+ end
293
+
294
+ def all_named_servers(server_name)
295
+ # ***connect.servers.all does not accept any arguments in GCP***
296
+
297
+ # create empty array
298
+ named_servers=Array.new
299
+ # get all servers
300
+ connect.servers.all.each do | returned_server |
301
+ # if the server name matches what we are looking for add to the result array
302
+ if returned_server.name == server_name
303
+ named_servers.push(returned_server)
304
+ end
305
+ end
306
+ # return the list of servers
307
+ named_servers
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright 2015 Adaptavist.com Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative './cloud_server.rb'
16
+ using Rainbow
17
+ module AvstCloud
18
+ class GcpServer < AvstCloud::CloudServer
19
+
20
+ def stop
21
+ if @server
22
+ logger.debug "Stopping #{@server_name}"
23
+ @server.stop
24
+ wait_for_state() {|serv| serv.status == 'TERMINATED'}
25
+ logger.debug "[DONE]\n\n"
26
+ logger.debug "Server #{@server_name} stopped...".green
27
+ else
28
+ raise "Server #{@server_name} does not exist!".red
29
+ end
30
+ end
31
+
32
+ def start
33
+ if @server
34
+ logger.debug "Starting #{@server_name}"
35
+ @server.start
36
+ wait_for_state() {|serv| serv.ready?}
37
+ logger.debug "[DONE]\n\n"
38
+ logger.debug "Server #{@server_name} started...".green
39
+ else
40
+ raise "Server #{@server_name} does not exist!".red
41
+ end
42
+ end
43
+
44
+ def destroy
45
+ if @server
46
+ logger.debug "Killing #{@server_name}"
47
+ @server.destroy
48
+ logger.debug "Server #{@server_name} destroying...".green
49
+ else
50
+ raise "Server #{@server_name} does not exist!".red
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -176,9 +176,8 @@ module AvstCloud
176
176
  if hdd.state == expected_state
177
177
  break
178
178
  end
179
- logger.debug(.)
180
179
  sleep 60
181
180
  end
182
181
  end
183
182
  end
184
- end
183
+ end
@@ -54,10 +54,6 @@ task :prepare_puppet_and_execute do
54
54
  execute :link_puppet
55
55
  execute :link_hiera
56
56
 
57
- if File.exist?("#{ENV["avst_cloud_config_dir"]}/keys")
58
- upload! "#{ENV["avst_cloud_config_dir"]}/keys", "/etc/puppet/config", recursive: true
59
- end
60
-
61
57
  within '/etc/puppet' do
62
58
  begin
63
59
  execute :execute_puppet_runner
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avst-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.35
4
+ version: 0.1.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Brehovsky
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-10-03 00:00:00.000000000 Z
13
+ date: 2021-04-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: 1.16.1
21
+ version: 1.17.3
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: 1.16.1
28
+ version: 1.17.3
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rake
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -69,47 +69,19 @@ dependencies:
69
69
  - !ruby/object:Gem::Version
70
70
  version: 1.43.0
71
71
  - !ruby/object:Gem::Dependency
72
- name: fog-azure
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - ">="
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :runtime
79
- prerelease: false
80
- version_requirements: !ruby/object:Gem::Requirement
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: '0'
85
- - !ruby/object:Gem::Dependency
86
- name: fog-azure-rm
72
+ name: fog-google
87
73
  requirement: !ruby/object:Gem::Requirement
88
74
  requirements:
89
75
  - - '='
90
76
  - !ruby/object:Gem::Version
91
- version: 0.0.3
77
+ version: 1.8.2
92
78
  type: :runtime
93
79
  prerelease: false
94
80
  version_requirements: !ruby/object:Gem::Requirement
95
81
  requirements:
96
82
  - - '='
97
83
  - !ruby/object:Gem::Version
98
- version: 0.0.3
99
- - !ruby/object:Gem::Dependency
100
- name: azure
101
- requirement: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: '0'
106
- type: :runtime
107
- prerelease: false
108
- version_requirements: !ruby/object:Gem::Requirement
109
- requirements:
110
- - - ">="
111
- - !ruby/object:Gem::Version
112
- version: '0'
84
+ version: 1.8.2
113
85
  - !ruby/object:Gem::Dependency
114
86
  name: rvm-capistrano
115
87
  requirement: !ruby/object:Gem::Requirement
@@ -224,18 +196,32 @@ dependencies:
224
196
  version: 3.0.0
225
197
  - !ruby/object:Gem::Dependency
226
198
  name: nokogiri
199
+ requirement: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - "~>"
202
+ - !ruby/object:Gem::Version
203
+ version: 1.8.5
204
+ type: :runtime
205
+ prerelease: false
206
+ version_requirements: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - "~>"
209
+ - !ruby/object:Gem::Version
210
+ version: 1.8.5
211
+ - !ruby/object:Gem::Dependency
212
+ name: signet
227
213
  requirement: !ruby/object:Gem::Requirement
228
214
  requirements:
229
215
  - - '='
230
216
  - !ruby/object:Gem::Version
231
- version: 1.8.2
217
+ version: 0.14.1
232
218
  type: :runtime
233
219
  prerelease: false
234
220
  version_requirements: !ruby/object:Gem::Requirement
235
221
  requirements:
236
222
  - - '='
237
223
  - !ruby/object:Gem::Version
238
- version: 1.8.2
224
+ version: 0.14.1
239
225
  description: Automated creation, bootstrapping and provisioning of servers
240
226
  email:
241
227
  - mbrehovsky@adaptavist.com
@@ -260,6 +246,7 @@ files:
260
246
  - bin/avst-cloud
261
247
  - bin/avst-cloud-azure
262
248
  - bin/avst-cloud-azure-rm
249
+ - bin/avst-cloud-gcp
263
250
  - bin/avst-cloud-puppet
264
251
  - bin/avst-cloud-rackspace
265
252
  - config/custom_system_config/hiera-configs/defaults/example.yaml
@@ -277,6 +264,8 @@ files:
277
264
  - lib/avst-cloud/azure_server.rb
278
265
  - lib/avst-cloud/cloud_connection.rb
279
266
  - lib/avst-cloud/cloud_server.rb
267
+ - lib/avst-cloud/gcp_connection.rb
268
+ - lib/avst-cloud/gcp_server.rb
280
269
  - lib/avst-cloud/logging.rb
281
270
  - lib/avst-cloud/rackspace_connection.rb
282
271
  - lib/avst-cloud/rackspace_server.rb
@@ -300,8 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
300
289
  - !ruby/object:Gem::Version
301
290
  version: '0'
302
291
  requirements: []
303
- rubyforge_project:
304
- rubygems_version: 2.7.7
292
+ rubygems_version: 3.0.8
305
293
  signing_key:
306
294
  specification_version: 4
307
295
  summary: Automated creation, bootstrapping and provisioning of servers