sitefull-cloud 0.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 +7 -0
- data/.codeclimate.yml +25 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1152 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +157 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/sitefull-cloud/auth/amazon.rb +53 -0
- data/lib/sitefull-cloud/auth/azure.rb +49 -0
- data/lib/sitefull-cloud/auth/base.rb +33 -0
- data/lib/sitefull-cloud/auth/google.rb +41 -0
- data/lib/sitefull-cloud/auth.rb +41 -0
- data/lib/sitefull-cloud/mock.rb +9 -0
- data/lib/sitefull-cloud/provider/amazon/networking.rb +87 -0
- data/lib/sitefull-cloud/provider/amazon.rb +61 -0
- data/lib/sitefull-cloud/provider/azure.rb +47 -0
- data/lib/sitefull-cloud/provider/base.rb +21 -0
- data/lib/sitefull-cloud/provider/google.rb +86 -0
- data/lib/sitefull-cloud/provider/mock.rb +41 -0
- data/lib/sitefull-cloud/provider.rb +44 -0
- data/lib/sitefull-cloud/version.rb +5 -0
- data/lib/sitefull-cloud.rb +23 -0
- data/sitefull-cloud.gemspec +40 -0
- metadata +254 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Sitefull
|
4
|
+
module Cloud
|
5
|
+
class Auth
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@provider, :token_options, :authorization_url_options
|
8
|
+
|
9
|
+
def initialize(provider_type, options = {})
|
10
|
+
token_set = !options[:token].to_s.empty?
|
11
|
+
token(JSON.parse options[:token]) if token_set
|
12
|
+
@provider = provider_class(provider_type).new(options, token_set)
|
13
|
+
end
|
14
|
+
|
15
|
+
def authorization_url
|
16
|
+
token.authorization_uri(authorization_url_options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def authorize!(code)
|
20
|
+
token.code = code
|
21
|
+
token.fetch_access_token!
|
22
|
+
end
|
23
|
+
|
24
|
+
def token(token_data = nil)
|
25
|
+
@token ||= Signet::OAuth2::Client.new(token_data.nil? ? token_options : token_data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def credentials
|
29
|
+
token.refresh!
|
30
|
+
@credentials ||= @provider.credentials(token)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def provider_class(provider_type)
|
36
|
+
require "sitefull-cloud/auth/#{provider_type}"
|
37
|
+
Kernel.const_get "Sitefull::Auth::#{provider_type.capitalize}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Sitefull
|
2
|
+
module Provider
|
3
|
+
module Amazon
|
4
|
+
module Networking
|
5
|
+
TEMPLATE_TAG = 'SiteFull Deployment'.freeze
|
6
|
+
VPC_CIDR_BLOCK = '172.16.0.0/16'.freeze
|
7
|
+
SUBNET_CIDR_BLOCK = '172.16.1.0/24'.freeze
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def vpc
|
12
|
+
@vpc ||= connection.describe_vpcs.vpcs.reverse.find { |v| check_tags(v) } || create_vpc
|
13
|
+
end
|
14
|
+
alias setup_vpc vpc
|
15
|
+
|
16
|
+
def internet_gateway
|
17
|
+
@internet_gateway ||= connection.describe_internet_gateways.internet_gateways.reverse.find { |i| check_internet_gateway(i) } || create_internet_gateway
|
18
|
+
end
|
19
|
+
alias setup_internet_gateway internet_gateway
|
20
|
+
|
21
|
+
def route_table
|
22
|
+
@route_table ||= connection.describe_route_tables.route_tables.reverse.find { |rt| rt.vpc_id == vpc.vpc_id }
|
23
|
+
end
|
24
|
+
|
25
|
+
def security_group
|
26
|
+
@security_group ||= connection.describe_security_groups.security_groups.reverse.find { |sg| sg.vpc_id == vpc.vpc_id }
|
27
|
+
end
|
28
|
+
|
29
|
+
def subnet
|
30
|
+
@subnet ||= connection.describe_subnets.subnets.reverse.find { |sg| check_tags(sg) } || create_subnet
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup_routing
|
34
|
+
add_routing unless check_tags(route_table)
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup_security_group
|
38
|
+
add_security_group_rules unless check_tags(security_group)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def create_vpc
|
44
|
+
vpc = connection.create_vpc(cidr_block: VPC_CIDR_BLOCK).vpc
|
45
|
+
add_tags(vpc.vpc_id)
|
46
|
+
vpc
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_internet_gateway(internet_gateway)
|
50
|
+
internet_gateway.attachments.map(&:vpc_id).include?(vpc.vpc_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_internet_gateway
|
54
|
+
internet_gateway = connection.create_internet_gateway.internet_gateway
|
55
|
+
add_tags(internet_gateway.internet_gateway_id) unless check_tags(internet_gateway)
|
56
|
+
connection.attach_internet_gateway(internet_gateway_id: internet_gateway.internet_gateway_id, vpc_id: vpc.vpc_id)
|
57
|
+
internet_gateway
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_routing
|
61
|
+
connection.create_route(route_table_id: route_table.route_table_id, destination_cidr_block: '0.0.0.0/0', gateway_id: internet_gateway.internet_gateway_id)
|
62
|
+
add_tags(route_table.route_table_id)
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_security_group_rules
|
66
|
+
connection.authorize_security_group_ingress(group_id: security_group.group_id, ip_protocol: 'tcp', from_port: 22, to_port: 22, cidr_ip: '0.0.0.0/0')
|
67
|
+
add_tags(security_group.group_id)
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_subnet
|
71
|
+
subnet = connection.create_subnet(vpc_id: vpc.vpc_id, cidr_block: SUBNET_CIDR_BLOCK).subnet
|
72
|
+
add_tags(subnet.subnet_id) unless check_tags(subnet)
|
73
|
+
connection.modify_subnet_attribute(subnet_id: subnet.subnet_id, map_public_ip_on_launch: { value: true })
|
74
|
+
subnet
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_tags(resource_id)
|
78
|
+
connection.create_tags resources: [resource_id], tags: [{ key: 'Name', value: TEMPLATE_TAG }]
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_tags(resource)
|
82
|
+
resource.tags.map(&:value).include?(TEMPLATE_TAG)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sitefull-cloud/provider/amazon/networking'
|
2
|
+
|
3
|
+
module Sitefull
|
4
|
+
module Provider
|
5
|
+
module Amazon
|
6
|
+
include Networking
|
7
|
+
|
8
|
+
REQUIRED_OPTIONS = [:role_arn].freeze
|
9
|
+
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
|
10
|
+
|
11
|
+
DEFAULT_REGION = 'us-east-1'.freeze
|
12
|
+
|
13
|
+
def connection
|
14
|
+
@connection ||= ::Aws::EC2::Client.new(region: options[:region] || DEFAULT_REGION, credentials: credentials)
|
15
|
+
end
|
16
|
+
|
17
|
+
def regions
|
18
|
+
@regions ||= connection.describe_regions.regions.map { |r| OpenStruct.new(id: r.region_name, name: r.region_name) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def machine_types(_)
|
22
|
+
MACHINE_TYPES.map { |mt| OpenStruct.new(id: mt, name: mt) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def images(os)
|
26
|
+
# IMAGES[os.to_sym]
|
27
|
+
filters = [{ name: 'name', values: ["#{os}*", "#{os.downcase}*"] }, { name: 'is-public', values: ['true'] }, { name: 'virtualization-type', values: ['hvm'] }]
|
28
|
+
connection.describe_images(filters: filters).images.map { |i| OpenStruct.new(id: i.image_id, name: i.name) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_network
|
32
|
+
setup_vpc
|
33
|
+
setup_internet_gateway
|
34
|
+
setup_routing
|
35
|
+
subnet.subnet_id
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_key(name)
|
39
|
+
result = connection.create_key_pair(key_name: name)
|
40
|
+
OpenStruct.new(name: result.key_name, data: result.key_material)
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_firewall_rules(_)
|
44
|
+
setup_security_group
|
45
|
+
end
|
46
|
+
|
47
|
+
# Uses http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Client.html#run_instances-instance_method
|
48
|
+
def create_instance(deployment)
|
49
|
+
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
|
50
|
+
end
|
51
|
+
|
52
|
+
def valid?
|
53
|
+
connection.describe_regions(dry_run: true)
|
54
|
+
rescue ::Aws::EC2::Errors::DryRunOperation
|
55
|
+
true
|
56
|
+
rescue StandardError
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Sitefull
|
2
|
+
module Provider
|
3
|
+
module Azure
|
4
|
+
REQUIRED_OPTIONS = [:subscription_id].freeze
|
5
|
+
|
6
|
+
def connection
|
7
|
+
# @connection ||= {
|
8
|
+
# arm: ::Azure::ARM::Resources::ResourceManagementClient.new(credentials),
|
9
|
+
# net: ::Azure::ARM::Network::NetworkResourceProviderClient.new(credentials),
|
10
|
+
# compute: ::Azure::ARM::Compute::ComputeManagementClient.new(credentials)
|
11
|
+
# }
|
12
|
+
end
|
13
|
+
|
14
|
+
def regions
|
15
|
+
['us']
|
16
|
+
end
|
17
|
+
|
18
|
+
def machine_types(region)
|
19
|
+
["machine-type-#{region}"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def images(os)
|
23
|
+
["image-region-#{os}"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_network
|
27
|
+
'network_id'
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_firewall_rules(network_id)
|
31
|
+
network_id
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_key(key_name)
|
35
|
+
OpenStruct.new(name: key_name, data: {})
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_instance(deployment)
|
39
|
+
deployment
|
40
|
+
end
|
41
|
+
|
42
|
+
def valid?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'google/apis/compute_v1'
|
2
|
+
|
3
|
+
module Sitefull
|
4
|
+
module Provider
|
5
|
+
module Google
|
6
|
+
REQUIRED_OPTIONS = [:project_name].freeze
|
7
|
+
|
8
|
+
def connection
|
9
|
+
return @connection unless @connection.nil?
|
10
|
+
|
11
|
+
connection = ::Google::Apis::ComputeV1::ComputeService.new
|
12
|
+
connection.authorization = credentials
|
13
|
+
@connection = connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def project_name
|
17
|
+
@project_name ||= options[:project_name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def regions
|
21
|
+
@regions ||= connection.list_zones(project_name).items
|
22
|
+
end
|
23
|
+
|
24
|
+
def machine_types(zone)
|
25
|
+
@machine_types ||= connection.list_machine_types(project_name, zone).items
|
26
|
+
rescue ::Google::Apis::ClientError
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def images(os)
|
31
|
+
@images ||= project_images(project_name) + project_images("#{os}-cloud")
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_network
|
35
|
+
return network_id unless network_id.nil?
|
36
|
+
|
37
|
+
network = ::Google::Apis::ComputeV1::Network.new(name: 'sitefull-cloud', i_pv4_range: '172.16.0.0/16')
|
38
|
+
connection.insert_network(project_name, network).target_link
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_firewall_rules(network_id)
|
42
|
+
create_firewall_rule(network_id, 'sitefull-ssh', '22')
|
43
|
+
create_firewall_rule(network_id, 'sitefull-http', '80')
|
44
|
+
create_firewall_rule(network_id, 'sitefull-https', '443')
|
45
|
+
network_id
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_key(_name)
|
49
|
+
OpenStruct.new(name: :key_name, data: :key_material)
|
50
|
+
end
|
51
|
+
|
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
|
57
|
+
end
|
58
|
+
|
59
|
+
def valid?
|
60
|
+
regions.any?
|
61
|
+
rescue StandardError
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def project_images(project)
|
68
|
+
images = connection.list_images(project).items
|
69
|
+
images.nil? || images.empty? ? [] : images.reject { |r| !r.deprecated.nil? && r.deprecated.state == 'DEPRECATED' }
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_firewall_rule(network_id, rule_name, port)
|
73
|
+
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
|
+
connection.insert_firewall(project_name, rule)
|
75
|
+
rescue ::Google::Apis::ClientError
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def network_id
|
80
|
+
@network ||= connection.get_network(project_name, 'sitefull-cloud').self_link
|
81
|
+
rescue ::Google::Apis::ClientError
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sitefull
|
2
|
+
module Provider
|
3
|
+
module Mock
|
4
|
+
def regions
|
5
|
+
mock_list 'region'
|
6
|
+
end
|
7
|
+
|
8
|
+
def machine_types(_region)
|
9
|
+
mock_list 'machine-type'
|
10
|
+
end
|
11
|
+
|
12
|
+
def images(_os)
|
13
|
+
mock_list 'image'
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_network
|
17
|
+
'network-id'
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_key(name)
|
21
|
+
OpenStruct.new(name: name, data: 'key-data')
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_firewall_rules(_)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_instance(_)
|
28
|
+
'instance-id'
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def mock_list(prefix)
|
37
|
+
Array.new(5) { |i| OpenStruct.new(id: "#{prefix}-id-#{i}", name: "#{prefix}-name-#{i}") }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Sitefull
|
2
|
+
module Cloud
|
3
|
+
class Provider
|
4
|
+
include Mock
|
5
|
+
PROVIDERS = %w(amazon azure google)
|
6
|
+
|
7
|
+
attr_reader :type, :options
|
8
|
+
|
9
|
+
def initialize(type, options = {})
|
10
|
+
@options = options unless options.nil?
|
11
|
+
@type = type || 'base'
|
12
|
+
extend(provider_module)
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def all_required_options
|
17
|
+
PROVIDERS.map { |type| required_options_for(type) }.flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def required_options_for(type)
|
21
|
+
provider_class(type).const_get(:REQUIRED_OPTIONS)
|
22
|
+
end
|
23
|
+
|
24
|
+
def provider_class(type)
|
25
|
+
require "sitefull-cloud/provider/#{type}"
|
26
|
+
Kernel.const_get "Sitefull::Provider::#{type.capitalize}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def credentials
|
33
|
+
@credentials ||= Sitefull::Cloud::Auth.new(type, options).credentials
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def provider_module
|
39
|
+
return self.class.provider_class(:mock) if mocked?
|
40
|
+
@provider_module ||= self.class.provider_class(type)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|