sitefull-cloud 0.0.4 → 0.1

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