File: server.rb

package info (click to toggle)
ruby-fog-aws 3.3.0-5
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 7,816 kB
  • sloc: ruby: 68,587; makefile: 6
file content (270 lines) | stat: -rw-r--r-- 10,322 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
require 'fog/compute/models/server'

module Fog
  module AWS
    class Compute
      class Server < Fog::Compute::Server
        extend Fog::Deprecation
        deprecate :ip_address, :public_ip_address

        identity  :id,                       :aliases => 'instanceId'

        attr_accessor :architecture
        attribute :ami_launch_index,         :aliases => 'amiLaunchIndex'
        attribute :associate_public_ip,      :aliases => 'associatePublicIP'
        attribute :availability_zone,        :aliases => 'availabilityZone'
        attribute :block_device_mapping,     :aliases => 'blockDeviceMapping'
        attribute :network_interfaces,       :aliases => 'networkInterfaces'
        attribute :client_token,             :aliases => 'clientToken'
        attribute :disable_api_termination,  :aliases => 'disableApiTermination'
        attribute :dns_name,                 :aliases => 'dnsName'
        attribute :ebs_optimized,            :aliases => 'ebsOptimized'
        attribute :groups
        attribute :flavor_id,                :aliases => 'instanceType'
        attribute :hypervisor
        attribute :iam_instance_profile,     :aliases => 'iamInstanceProfile'
        attribute :image_id,                 :aliases => 'imageId'
        attr_accessor :instance_initiated_shutdown_behavior
        attribute :kernel_id,                :aliases => 'kernelId'
        attribute :key_name,                 :aliases => 'keyName'
        attribute :created_at,               :aliases => 'launchTime'
        attribute :lifecycle,                :aliases => 'instanceLifecycle'
        attribute :monitoring,               :squash =>  'state'
        attribute :placement_group,          :aliases => 'groupName'
        attribute :platform,                 :aliases => 'platform'
        attribute :product_codes,            :aliases => 'productCodes'
        attribute :private_dns_name,         :aliases => 'privateDnsName'
        attribute :private_ip_address,       :aliases => 'privateIpAddress'
        attribute :public_ip_address,        :aliases => 'ipAddress'
        attribute :ramdisk_id,               :aliases => 'ramdiskId'
        attribute :reason
        attribute :requester_id,             :aliases => 'requesterId'
        attribute :root_device_name,         :aliases => 'rootDeviceName'
        attribute :root_device_type,         :aliases => 'rootDeviceType'
        attribute :security_group_ids,       :aliases => 'securityGroupIds'
        attribute :source_dest_check,        :aliases => 'sourceDestCheck'
        attribute :spot_instance_request_id, :aliases => 'spotInstanceRequestId'
        attribute :state,                    :aliases => 'instanceState', :squash => 'name'
        attribute :state_reason,             :aliases => 'stateReason'
        attribute :subnet_id,                :aliases => 'subnetId'
        attribute :tenancy
        attribute :tags,                     :aliases => 'tagSet'
        attribute :user_data
        attribute :virtualization_type,      :aliases => 'virtualizationType'
        attribute :vpc_id,                   :aliases => 'vpcId'

        attr_accessor                        :password
        attr_writer                          :iam_instance_profile_name, :iam_instance_profile_arn

        def initialize(attributes={})
          self.groups     ||= ["default"] unless (attributes[:subnet_id] || attributes[:security_group_ids] || attributes[:network_interfaces])
          self.flavor_id  ||= 't1.micro'

          # Old 'connection' is renamed as service and should be used instead
          prepare_service_value(attributes)

          self.image_id   ||= begin
            self.username ||= 'ubuntu'
            case @service.instance_variable_get(:@region) # Ubuntu 10.04 LTS 64bit (EBS)
            when 'ap-northeast-1'
              'ami-5e0fa45f'
            when 'ap-southeast-1'
              'ami-f092eca2'
            when 'ap-southeast-2'
              'ami-fb8611c1' # Ubuntu 12.04 LTS 64bit (EBS)
            when 'eu-west-1'
              'ami-3d1f2b49'
            when 'sa-east-1'
              'ami-d0429ccd'
            when 'us-east-1'
              'ami-3202f25b'
            when 'us-west-1'
              'ami-f5bfefb0'
            when 'us-west-2'
              'ami-e0ec60d0'
            end
          end
          super
        end

        def addresses
          requires :id

          service.addresses(:server => self)
        end

        def console_output
          requires :id

          service.get_console_output(id)
        end

        def destroy
          requires :id

          service.terminate_instances(id)
          true
        end

        remove_method :flavor_id
        def flavor_id
          @flavor && @flavor.id || attributes[:flavor_id]
        end

        def flavor=(new_flavor)
          @flavor = new_flavor
        end

        def flavor
          @flavor ||= service.flavors.all.find {|flavor| flavor.id == flavor_id}
        end

        def key_pair
          requires :key_name
          service.key_pairs.all({'key-name' => key_name}).first
        end

        def key_pair=(new_keypair)
          self.key_name = new_keypair && new_keypair.name
        end

        def ready?
          state == 'running'
        end

        def reboot
          requires :id
          service.reboot_instances(id)
          true
        end

        def run_instance_options
          raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
          requires :image_id

          options = {
            'BlockDeviceMapping'          => block_device_mapping,
            'NetworkInterfaces'           => network_interfaces,
            'ClientToken'                 => client_token,
            'DisableApiTermination'       => disable_api_termination,
            'EbsOptimized'                => ebs_optimized,
            'IamInstanceProfile.Arn'      => @iam_instance_profile_arn,
            'IamInstanceProfile.Name'     => @iam_instance_profile_name,
            'InstanceInitiatedShutdownBehavior' => instance_initiated_shutdown_behavior,
            'InstanceType'                => flavor_id,
            'KernelId'                    => kernel_id,
            'KeyName'                     => key_name,
            'Monitoring.Enabled'          => monitoring,
            'Placement.AvailabilityZone'  => availability_zone,
            'Placement.GroupName'         => placement_group,
            'Placement.Tenancy'           => tenancy,
            'PrivateIpAddress'            => private_ip_address,
            'RamdiskId'                   => ramdisk_id,
            'SecurityGroup'               => groups,
            'SecurityGroupId'             => security_group_ids,
            'SubnetId'                    => subnet_id,
            'UserData'                    => user_data,
          }
          options.delete_if {|key, value| value.nil?}

          # If subnet is defined then this is a Virtual Private Cloud.
          # subnet & security group cannot co-exist. Attempting to specify
          # both subnet and groups will cause an error.  Instead please make
          # use of Security Group Ids when working in a VPC.
          if subnet_id
            options.delete('SecurityGroup')
            if associate_public_ip
              options['NetworkInterface.0.DeviceIndex'] = 0
              options['NetworkInterface.0.AssociatePublicIpAddress'] = associate_public_ip
              options['NetworkInterface.0.SubnetId'] = options['SubnetId']
              options.delete('SubnetId')
              if options['SecurityGroupId'].kind_of?(Array)
                options['SecurityGroupId'].each {|id|
                  options["NetworkInterface.0.SecurityGroupId.#{options['SecurityGroupId'].index(id)}"] = id
                }
              else
                options["NetworkInterface.0.SecurityGroupId.0"] = options['SecurityGroupId']
              end
              options.delete('SecurityGroupId')
              if private_ip_address
                options.delete('PrivateIpAddress')
                options['NetworkInterface.0.PrivateIpAddress'] = private_ip_address
              end
            end
          else
            options.delete('SubnetId')
          end
          options
        end

        def save
          servers = service.servers.save_many(self, 1, 1)
          merge_attributes(servers.first.attributes)
          true
        end

        def setup(credentials = {})
          requires :ssh_ip_address, :username

          commands = [
            %{mkdir .ssh},
            %{passwd -l #{username}},
            %{echo "#{Fog::JSON.encode(Fog::JSON.sanitize(attributes))}" >> ~/attributes.json}
          ]
          if public_key
            commands << %{echo "#{public_key}" >> ~/.ssh/authorized_keys}
          end

          # wait for aws to be ready
          wait_for { sshable?(credentials) }

          Fog::SSH.new(ssh_ip_address, username, credentials).run(commands)
        end

        def start
          requires :id
          service.start_instances(id)
          true
        end

        def stop(force = false)
          requires :id
          service.stop_instances(id, force)
          true
        end

        def volumes
          requires :id
          service.volumes(:server => self)
        end

        #I tried to call it monitoring= and be smart with attributes[]
        #but in #save a merge_attribute is called after run_instance
        #thus making an un-necessary request. Use this until finding a clever solution
        def monitor=(new_monitor)
          if persisted?
            case new_monitor
            when true
              response = service.monitor_instances(identity)
            when false
              response = service.unmonitor_instances(identity)
            else
              raise ArgumentError.new("only Boolean allowed here")
            end
          end
          self.monitoring = new_monitor
        end

        private

        def placement=(new_placement)
          if new_placement.is_a?(Hash)
            merge_attributes(new_placement)
          else
            self.attributes[:placement] = new_placement
          end
        end
      end
    end
  end
end