sitefull-cloud 0.0.4 → 0.1

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
  SHA1:
3
- metadata.gz: 5257926daababbafbf83a828de1ae95a9b155a4f
4
- data.tar.gz: fe53ea223c4da35fee4cefc93e41ec069b93aea6
3
+ metadata.gz: 92e6a59aa462576c96fe758d339417d7d4b31f32
4
+ data.tar.gz: b306b27f8b52c8392955d57f95146f8ab95a71e8
5
5
  SHA512:
6
- metadata.gz: 1f1be289d8c22195dc3af97883e009c7a25b08b0dd9c642706a5b4f78d7a66d4fb6f20458e262fea9cf8acc0a77c06a93438f0da8984b49237864a42b4a41f19
7
- data.tar.gz: c03f19f7db78471d4398c546852e38169de1af331967b7e094edab0205b71338e988d1f9fb8487b8041e06b4b486800fc8884cdb8951ad6d9470843cfee141cc
6
+ metadata.gz: 88d5c9e983102ee97effbc0d02afc7963f34913b469b41dbd3f41724e06632a3bd44fba8c8c8c36383cdc86bc5299738c6211690a35a2a32a4ecbcc1bdc01811
7
+ data.tar.gz: 8a7da3c1cb275a35a0079f38c51c9dace4cc72f6433a84af33dc8a3a4d195e66a9891ece6163db328eaac3f33086f0c0996f53b5c12c9fec92b444921d7cdb48
@@ -5,7 +5,7 @@ module Sitefull
5
5
  module Cloud
6
6
  class Auth
7
7
  extend Forwardable
8
- def_delegators :@auth, :token_options, :authorization_url_options
8
+ def_delegators :@auth, :token_options, :authorization_url_options, :required_settings
9
9
 
10
10
  def initialize(auth_type, options = {})
11
11
  @auth = auth_class(auth_type).new(options)
@@ -44,6 +44,10 @@ module Sitefull
44
44
  def token_credentials_uri(options)
45
45
  sprintf(TOKEN_CREDENTIALS_URI, options[:tenant_id])
46
46
  end
47
+
48
+ def required_settings
49
+ super << :tenant_id
50
+ end
47
51
  end
48
52
  end
49
53
  end
@@ -13,7 +13,7 @@ module Sitefull
13
13
  MISSING_TOKEN_CREDENTIALS_URI = 'Missing Token Credentials URL'.freeze
14
14
 
15
15
  def initialize(options = {})
16
- @options = validate(options)
16
+ @options = validate(options) if options[:validate].to_s.empty? || options[:validate]
17
17
  end
18
18
 
19
19
  def validate(options = {})
@@ -46,6 +46,11 @@ module Sitefull
46
46
  def token_credentials_uri(_)
47
47
  fail MISSING_TOKEN_CREDENTIALS_URI
48
48
  end
49
+
50
+ def required_settings
51
+ [:client_id, :client_secret]
52
+ end
53
+
49
54
  private
50
55
 
51
56
  def process(options = {})
@@ -1,3 +1,5 @@
1
+ require 'net/ssh'
2
+
1
3
  module Sitefull
2
4
  module Cloud
3
5
  class Provider
@@ -37,12 +39,21 @@ module Sitefull
37
39
  @credentials ||= auth.credentials
38
40
  end
39
41
 
42
+ def key_data
43
+ @key_data ||= generate_key_data
44
+ end
45
+
40
46
  private
41
47
 
42
48
  def provider_module
43
49
  return self.class.provider_class(:mock) if mocked?
44
50
  @provider_module ||= self.class.provider_class(type)
45
51
  end
52
+
53
+ def generate_key_data
54
+ key = OpenSSL::PKey::RSA.new 2048
55
+ { public_key: [ key.to_blob ].pack('m0'), private_key: key.to_s }
56
+ end
46
57
  end
47
58
  end
48
59
  end
@@ -6,10 +6,12 @@ module Sitefull
6
6
  module Amazon
7
7
  include Networking
8
8
 
9
- REQUIRED_OPTIONS = %w(role_arn region session_name).freeze
9
+ REQUIRED_OPTIONS = %w(role_arn session_name).freeze
10
10
  MACHINE_TYPES = %w(t2.nano t2.micro t2.small t2.medium t2.large m4.large m4.xlarge m4.2xlarge m4.4xlarge m4.10xlarge m3.medium m3.large m3.xlarge m3.2xlarge).freeze
11
11
 
12
12
  DEFAULT_REGION = 'us-east-1'.freeze
13
+ WAIT = 2.freeze
14
+ INSTANCE_RUNNING_STATE = 'running'.freeze
13
15
 
14
16
  def process(options = {})
15
17
  options[:region] ||= DEFAULT_REGION
@@ -41,23 +43,35 @@ module Sitefull
41
43
  end
42
44
 
43
45
  def create_key(name)
44
- result = connection.create_key_pair(key_name: name)
45
- OpenStruct.new(name: result.key_name, data: result.key_material)
46
+ connection.import_key_pair(key_name: name, public_key_material: "ssh-rsa #{key_data[:public_key]}")
47
+ OpenStruct.new(key_data)
46
48
  end
47
49
 
48
- def create_firewall_rules(_)
50
+ def create_firewall_rules
49
51
  setup_security_group
50
52
  end
51
53
 
52
54
  # Uses http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#run_instances-instance_method
53
- def create_instance(deployment)
54
- connection.run_instances(image_id: deployment.image, instance_type: deployment.machine_type, subnet_id: deployment.network_id, key_name: deployment.key_name, security_group_ids: [security_group.group_id], min_count: 1, max_count: 1).instances.first.instance_id
55
+ def create_instance(_name, machine_type, image, network_id, key)
56
+ instance = connection.run_instances(image_id: image, instance_type: machine_type,
57
+ subnet_id: network_id, key_name: key.name,
58
+ security_group_ids: [security_group.group_id], min_count: 1, max_count: 1).instances.first
59
+ sleep WAIT unless instance(instance.instance_id).state.name == INSTANCE_RUNNING_STATE
60
+ instance.instance_id
61
+ end
62
+
63
+ def instance_data(instance_id)
64
+ OpenStruct.new(id: instance_id, public_ip: instance(instance_id).public_ip_address)
55
65
  end
56
66
 
57
67
  def valid?
58
68
  !connection.nil?
59
- rescue StandardError
60
- false
69
+ end
70
+
71
+ private
72
+
73
+ def instance(instance_id)
74
+ connection.describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
61
75
  end
62
76
  end
63
77
  end
@@ -2,7 +2,7 @@ module Sitefull
2
2
  module Provider
3
3
  module Amazon
4
4
  module Networking
5
- TEMPLATE_TAG = 'SiteFull Deployment'.freeze
5
+ TEMPLATE_TAG = 'SiteFull Deployments'.freeze
6
6
  VPC_CIDR_BLOCK = '172.16.0.0/16'.freeze
7
7
  SUBNET_CIDR_BLOCK = '172.16.1.0/24'.freeze
8
8
 
@@ -43,6 +43,8 @@ module Sitefull
43
43
  def create_vpc
44
44
  vpc = connection.create_vpc(cidr_block: VPC_CIDR_BLOCK).vpc
45
45
  add_tags(vpc.vpc_id)
46
+ connection.modify_vpc_attribute(vpc_id: vpc.vpc_id, enable_dns_support: { value: true })
47
+ connection.modify_vpc_attribute(vpc_id: vpc.vpc_id, enable_dns_hostnames: { value: true })
46
48
  vpc
47
49
  end
48
50
 
@@ -11,7 +11,7 @@ module Sitefull
11
11
  include Networking
12
12
  include Instance
13
13
 
14
- REQUIRED_OPTIONS = %w(region subscription_id).freeze
14
+ REQUIRED_OPTIONS = %w(subscription_id).freeze
15
15
 
16
16
  IMAGES = {
17
17
  debian: { publisher: 'Credativ', offer: 'Debian' },
@@ -32,6 +32,9 @@ module Sitefull
32
32
  SECURITY_GROUP = 'sitefull'.freeze
33
33
  PUBLIC_IP_NAME = 'sitefull'.freeze
34
34
 
35
+ WAIT = 2.freeze
36
+ SUCCESS_PROVISIONING_STATE = 'Succeeded'.freeze
37
+
35
38
  def connection
36
39
  return @connection unless @connection.nil?
37
40
 
@@ -46,52 +49,62 @@ module Sitefull
46
49
  end
47
50
 
48
51
  def regions
49
- @regions ||= connection.arm.providers.get('Microsoft.Compute').value!.body.resource_types.find { |rt| rt.resource_type == 'virtualMachines' }.locations.map { |l| OpenStruct.new(id: l.downcase.gsub(/\s/, ''), name: l) }
52
+ @regions ||= connection.arm.providers.get('Microsoft.Compute').resource_types.find { |rt| rt.resource_type == 'virtualMachines' }.locations.map { |l| OpenStruct.new(id: l.downcase.gsub(/\s/, ''), name: l) }
50
53
  end
51
54
 
52
55
  def machine_types(region)
53
- @machine_types ||= connection.compute.virtual_machine_sizes.list(region).value!.body.value.map { |mt| OpenStruct.new(id: mt.name, name: mt.name) }
56
+ @machine_types ||= connection.compute.virtual_machine_sizes.list(region).value.map { |mt| OpenStruct.new(id: mt.name, name: mt.name) }
54
57
  end
55
58
 
56
59
  def images(os)
57
60
  @images unless @images.nil?
58
61
 
59
62
  search = IMAGES[os.to_sym]
60
- image_skus = connection.compute.virtual_machine_images.list_skus(options[:region], search[:publisher], search[:offer]).value!.body
63
+ image_skus = connection.compute.virtual_machine_images.list_skus(options[:region], search[:publisher], search[:offer])
61
64
  @images = image_skus.map { |sku| OpenStruct.new(id: "#{search[:publisher]}:#{search[:offer]}:#{sku.name}", name: "#{search[:offer]} #{sku.name}") }
62
65
  end
63
66
 
64
67
  def create_network
65
- resource_group = resource_group_setup.value!.body
68
+ resource_group = resource_group_setup
66
69
  security_group = security_group_setup.value!.body
67
70
  network = network_setup(resource_group, security_group).value!.body
68
71
  network.properties.subnets.last.name
69
72
  end
70
73
 
71
- def create_firewall_rules(_)
74
+ def create_firewall_rules
72
75
  inbound_firewall_rule 'ssh', '22', 100
73
76
  inbound_firewall_rule 'http', '80', 101
74
77
  inbound_firewall_rule 'https', '443', 102
75
78
  end
76
79
 
77
- def create_key(key_name)
78
- OpenStruct.new(name: key_name, data: {})
80
+ def create_key(_)
81
+ OpenStruct.new(key_data)
79
82
  end
80
83
 
81
- def create_instance(deployment)
82
- name = "sitefull-deployment-#{deployment.id}"
83
- subnet = connection.network.subnets.get(resource_group_name, NETWORK_NAME, SUBNET_NAME).value!.body
84
- security_group = connection.network.network_security_groups.get(resource_group_name, SECURITY_GROUP).value!.body
84
+ def create_instance(name, machine_type, image, network_id, key)
85
+ subnet = connection.network.subnets.get(resource_group_name, NETWORK_NAME, network_id)
86
+ security_group = connection.network.network_security_groups.get(resource_group_name, SECURITY_GROUP)
85
87
  public_ip = public_ip_setup(name).value!.body
86
88
  network_interface = network_interface_setup(subnet, security_group, public_ip, name).value!.body
87
- storage = storage_setup(name)
88
- instance_setup(storage, network_interface, deployment.machine_type, deployment.image, name).value!.body.name
89
+
90
+ storage_setup(name)
91
+ sleep WAIT unless storage_account(name).properties.provisioning_state == SUCCESS_PROVISIONING_STATE
92
+ storage = storage_account(name)
93
+
94
+ instance_data = {machine_type: machine_type, image: image, name: name, key: key}
95
+ instance_id = instance_setup(storage, network_interface, instance_data).value!.body.name
96
+ sleep WAIT unless instance(instance_id).properties.provisioning_state == SUCCESS_PROVISIONING_STATE
97
+ instance_id
98
+ end
99
+
100
+ def instance_data(instance_id)
101
+ OpenStruct.new(id: instance_id, public_ip: public_ip(instance_id))
89
102
  end
90
103
 
91
104
  def valid?
92
- !options[:subscription_id].empty? && !connection.empty?
93
- rescue StandardError
94
- false
105
+ !options[:subscription_id].empty? && !connection.empty? && !regions.empty?
106
+ rescue MsRestAzure::AzureOperationError => e
107
+ raise StandardError.new JSON.parse(e.response.body)['error']['message']
95
108
  end
96
109
 
97
110
  private
@@ -105,9 +118,6 @@ module Sitefull
105
118
  resource_group.location = options[:region]
106
119
  connection.arm.resource_groups.create_or_update(resource_group_name, resource_group)
107
120
  end
108
-
109
- def image_skus
110
- end
111
121
  end
112
122
  end
113
123
  end
@@ -10,9 +10,9 @@ module Sitefull
10
10
  include ::Azure::ARM::Network::Models
11
11
  include ::Azure::ARM::Storage::Models
12
12
 
13
- STORAGE_ACCOUNT_TYPE = 'Standard_LRS'.freeze
14
13
 
15
14
  private
15
+
16
16
  def network_interface_setup(subnet, security_group, public_ip, name)
17
17
  ip_configuration_props = NetworkInterfaceIPConfigurationPropertiesFormat.new
18
18
  ip_configuration_props.private_ipallocation_method = 'Dynamic'
@@ -51,45 +51,64 @@ module Sitefull
51
51
  connection.network.public_ipaddresses.create_or_update(resource_group_name, name, public_ip)
52
52
  end
53
53
 
54
+ def public_ip(name)
55
+ connection.network.public_ipaddresses.get(resource_group_name, name).properties.ip_address
56
+ end
57
+
54
58
  def storage_setup(name)
55
- storage_account = connection.storage.storage_accounts.list_by_resource_group(resource_group_name).value!.body.value.find { |sa| sa.name == storage_account_name(name) }
59
+ storage_account = storage_account(name)
56
60
  return storage_account unless storage_account.nil?
57
61
 
58
62
  properties = StorageAccountPropertiesCreateParameters.new
59
- properties.account_type = STORAGE_ACCOUNT_TYPE
63
+
64
+ sku = Sku.new
65
+ sku.name = 'Standard_LRS'
66
+ sku.tier = 'Standard'
60
67
 
61
68
  params = StorageAccountCreateParameters.new
62
69
  params.properties = properties
70
+ params.sku = sku
71
+ params.kind = 'Storage'
63
72
  params.location = options[:region]
64
73
 
65
74
  connection.storage.storage_accounts.create(resource_group_name, storage_account_name(name), params).value!.body
66
75
  end
67
76
 
68
- def instance_setup(storage, network_interface, machine_type, image, name)
77
+ def storage_account(name)
78
+ connection.storage.storage_accounts.list_by_resource_group(resource_group_name).value.find { |sa| sa.name == storage_account_name(name) }
79
+ end
80
+
81
+ def instance_setup(storage, network_interface, instance_data)
69
82
  # Create a model for new virtual machine
70
83
  props = VirtualMachineProperties.new
71
84
 
72
85
  #windows_config = WindowsConfiguration.new
73
86
  #windows_config.provision_vmagent = true
74
87
  #windows_config.enable_automatic_updates = true
88
+
89
+ ssh_key = SshPublicKey.new
90
+ ssh_key.path = "/home/#{instance_data[:key].ssh_user}/.ssh/authorized_keys"
91
+ ssh_key.key_data = "ssh-rsa #{instance_data[:key].public_key} #{instance_data[:key].ssh_user}"
92
+
93
+ ssh_config = SshConfiguration.new
94
+ ssh_config.public_keys = [ssh_key]
95
+
75
96
  linux_config = LinuxConfiguration.new
76
- linux_config.disable_password_authentication = false
97
+ linux_config.ssh = ssh_config
98
+ linux_config.disable_password_authentication = true
77
99
 
78
100
  os_profile = OSProfile.new
79
- os_profile.computer_name = name
80
- os_profile.admin_username = 'sitefull'
81
- os_profile.admin_password = 'P@ssword1'
101
+ os_profile.computer_name = instance_data[:name]
102
+ os_profile.admin_username = instance_data[:key].ssh_user
82
103
  os_profile.linux_configuration = linux_config
83
- # os_profile.custom_data = Base64.strict_encode64("#!/bin/sh\necho \"Hello World!\"").encode('utf-8')
84
104
 
85
- os_profile.secrets = []
86
105
  props.os_profile = os_profile
87
106
 
88
107
  hardware_profile = HardwareProfile.new
89
- hardware_profile.vm_size = machine_type
108
+ hardware_profile.vm_size = instance_data[:machine_type]
90
109
  props.hardware_profile = hardware_profile
91
110
 
92
- props.storage_profile = create_storage_profile(image, storage.name)
111
+ props.storage_profile = create_storage_profile(instance_data[:image], storage.name)
93
112
 
94
113
  network_profile = NetworkProfile.new
95
114
  network_profile.network_interfaces = [network_interface]
@@ -100,7 +119,11 @@ module Sitefull
100
119
  params.properties = props
101
120
  params.location = options[:region]
102
121
 
103
- connection.compute.virtual_machines.create_or_update(resource_group_name, name, params)
122
+ connection.compute.virtual_machines.create_or_update(resource_group_name, instance_data[:name], params)
123
+ end
124
+
125
+ def instance(instance_id)
126
+ connection.compute.virtual_machines.get(resource_group_name, instance_id)
104
127
  end
105
128
 
106
129
  def create_storage_profile(image, name)
@@ -1,9 +1,13 @@
1
1
  require 'google/apis/compute_v1'
2
+ Google::Apis::RequestOptions.default.retries = 5
2
3
 
3
4
  module Sitefull
4
5
  module Provider
5
6
  module Google
6
- REQUIRED_OPTIONS = [:project_name].freeze
7
+ REQUIRED_OPTIONS = %w(project_name).freeze
8
+
9
+ WAIT = 2.freeze
10
+ INSTANCE_RUNNING_STATE = 'RUNNING'.freeze
7
11
 
8
12
  def connection
9
13
  return @connection unless @connection.nil?
@@ -38,28 +42,32 @@ module Sitefull
38
42
  connection.insert_network(project_name, network).target_link
39
43
  end
40
44
 
41
- def create_firewall_rules(network_id)
45
+ def create_firewall_rules
42
46
  create_firewall_rule(network_id, 'sitefull-ssh', '22')
43
47
  create_firewall_rule(network_id, 'sitefull-http', '80')
44
48
  create_firewall_rule(network_id, 'sitefull-https', '443')
45
- network_id
46
49
  end
47
50
 
48
- def create_key(_name)
49
- OpenStruct.new(name: :key_name, data: :key_material)
51
+ def create_key(_)
52
+ OpenStruct.new(key_data)
53
+ end
54
+
55
+ def create_instance(name, machine_type, image, network_id, key)
56
+ instance = ::Google::Apis::ComputeV1::Instance.new(name: name, machine_type: machine_type,
57
+ disks: [{ boot: true, autoDelete: true, initialize_params: { source_image: image } }],
58
+ network_interfaces: [{ network: network_id, access_configs: [{ name: 'default' }] }],
59
+ metadata: { items: [{ key: 'ssh-keys', value: "#{key.ssh_user}:ssh-rsa #{key.public_key} #{key.ssh_user}"}] })
60
+ connection.insert_instance(project_name, options[:region], instance).target_link
61
+ sleep WAIT unless instance(name).status == INSTANCE_RUNNING_STATE
62
+ name
50
63
  end
51
64
 
52
- def create_instance(deployment)
53
- instance = ::Google::Apis::ComputeV1::Instance.new(name: "sitefull-deployment-#{deployment.id}", machine_type: deployment.machine_type,
54
- disks: [{ boot: true, autoDelete: true, initialize_params: { source_image: deployment.image } }],
55
- network_interfaces: [{ network: deployment.network_id, access_configs: [{ name: 'default' }] }])
56
- connection.insert_instance(project_name, deployment.region, instance).target_link
65
+ def instance_data(instance_id)
66
+ OpenStruct.new(id: instance_id, public_ip: instance(instance_id).network_interfaces.first.access_configs.first.nat_ip)
57
67
  end
58
68
 
59
69
  def valid?
60
70
  regions.any?
61
- rescue StandardError
62
- false
63
71
  end
64
72
 
65
73
  private
@@ -70,10 +78,15 @@ module Sitefull
70
78
  end
71
79
 
72
80
  def create_firewall_rule(network_id, rule_name, port)
81
+ return if firewall_rule_exists?(rule_name)
73
82
  rule = ::Google::Apis::ComputeV1::Firewall.new(name: rule_name, source_ranges: ['0.0.0.0/0'], network: network_id, allowed: [{ ip_protocol: 'tcp', ports: [port] }])
74
83
  connection.insert_firewall(project_name, rule)
84
+ end
85
+
86
+ def firewall_rule_exists?(rule_name)
87
+ connection.get_firewall(project_name, rule_name)
75
88
  rescue ::Google::Apis::ClientError
76
- nil
89
+ false
77
90
  end
78
91
 
79
92
  def network_id
@@ -81,6 +94,10 @@ module Sitefull
81
94
  rescue ::Google::Apis::ClientError
82
95
  nil
83
96
  end
97
+
98
+ def instance(instance_id)
99
+ connection.get_instance(project_name, options[:region], instance_id)
100
+ end
84
101
  end
85
102
  end
86
103
  end
@@ -17,17 +17,21 @@ module Sitefull
17
17
  'network-id'
18
18
  end
19
19
 
20
- def create_key(name)
21
- OpenStruct.new(name: name, data: 'key-data')
20
+ def create_key(_name)
21
+ OpenStruct.new(ssh_user: 'ssh_user', public_key: 'public_key', private_key: 'private_key')
22
22
  end
23
23
 
24
- def create_firewall_rules(_)
24
+ def create_firewall_rules
25
25
  end
26
26
 
27
- def create_instance(_)
27
+ def create_instance(_, _, _, _, _)
28
28
  'instance-id'
29
29
  end
30
30
 
31
+ def instance_data(instance_id)
32
+ OpenStruct.new(id: instance_id, public_ip: 'public_ip')
33
+ end
34
+
31
35
  def valid?
32
36
  true
33
37
  end
@@ -1,5 +1,5 @@
1
1
  module Sitefull
2
2
  module Cloud
3
- VERSION = '0.0.4'
3
+ VERSION = '0.1'
4
4
  end
5
5
  end
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency 'azure_mgmt_resources'
35
35
  spec.add_dependency 'azure_mgmt_storage'
36
36
  spec.add_dependency 'activesupport'
37
+ spec.add_dependency 'net-ssh'
37
38
 
38
39
  spec.add_development_dependency "bundler"
39
40
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sitefull-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: '0.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanimir Dimitrov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-15 00:00:00.000000000 Z
11
+ date: 2016-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: net-ssh
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: bundler
169
183
  requirement: !ruby/object:Gem::Requirement