Class: Kitsune::Kit::Adapters::DigitalOceanProvider

Inherits:
Provider
  • Object
show all
Defined in:
lib/kitsune/kit/adapters/digitalocean_provider.rb

Constant Summary collapse

POLL_INTERVAL =
5

Instance Method Summary collapse

Constructor Details

#initialize(token:, client: nil, sleeper: Kernel, maximum_timeout: nil) ⇒ DigitalOceanProvider

Returns a new instance of DigitalOceanProvider.



13
14
15
16
17
18
19
20
21
22
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 13

def initialize(token:, client: nil, sleeper: Kernel, maximum_timeout: nil)
  super()
  raise Errors::AuthenticationError, "DigitalOcean token is missing" if token.to_s.empty?
  if maximum_timeout && maximum_timeout <= 0
    raise Errors::ConfigurationError, "timeout must be greater than zero"
  end

  @client = client || build_client(token, maximum_timeout)
  @sleeper = sleeper
end

Instance Method Details

#create_server(spec:) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 66

def create_server(spec:)
  droplet = DropletKit::Droplet.new(
    name: spec.fetch(:name),
    region: spec.fetch(:region),
    size: spec.fetch(:size),
    image: spec.fetch(:image),
    ssh_keys: [spec.fetch(:ssh_key_id)],
    tags: spec.fetch(:tags, [])
  )
  server_record(@client.droplets.create(droplet))
rescue StandardError => e
  raise_provider_error("Unable to create DigitalOcean server #{spec[:name]}", e)
end

#delete_dns_record(id:, zone:) ⇒ Object



128
129
130
131
132
133
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 128

def delete_dns_record(id:, zone:)
  @client.domain_records.delete(for_domain: zone, id: id)
  true
rescue StandardError => e
  raise_provider_error("Unable to delete DNS record #{id} from #{zone}", e)
end

#delete_server(id:) ⇒ Object



100
101
102
103
104
105
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 100

def delete_server(id:)
  @client.droplets.delete(id: id)
  true
rescue StandardError => e
  raise_provider_error("Unable to delete DigitalOcean server #{id}", e)
end

#find_dns_record(zone:, name:, type:) ⇒ Object



107
108
109
110
111
112
113
114
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 107

def find_dns_record(zone:, name:, type:)
  record = @client.domain_records.all(for_domain: zone).find do |candidate|
    candidate.name == name && candidate.type == type
  end
  record && dns_record(zone, record)
rescue StandardError => e
  raise_provider_error("Unable to inspect DNS record #{name}.#{zone}", e)
end

#find_server(name:, tags: []) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 47

def find_server(name:, tags: [])
  tag = tags.first
  droplets = tag ? @client.droplets.all(tag_name: tag) : @client.droplets.all
  droplet = droplets.find do |candidate|
    candidate.name == name && (tags - Array(candidate.tags)).empty?
  end
  droplet && server_record(droplet)
rescue StandardError => e
  raise_provider_error("Unable to find DigitalOcean server #{name}", e)
end

#find_server_by_id(id:) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 58

def find_server_by_id(id:)
  server_record(@client.droplets.find(id: id))
rescue StandardError => e
  return nil if not_found?(e)

  raise_provider_error("Unable to find DigitalOcean server #{id}", e)
end

#upsert_dns_record(record:) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 116

def upsert_dns_record(record:)
  value = DropletKit::DomainRecord.new(type: record.type, name: record.name, data: record.data, ttl: record.ttl)
  saved = if record.id
            @client.domain_records.update(value, for_domain: record.zone, id: record.id)
          else
            @client.domain_records.create(value, for_domain: record.zone)
          end
  dns_record(record.zone, saved)
rescue StandardError => e
  raise_provider_error("Unable to update DNS record #{record.name}.#{record.zone}", e)
end

#validate_credentials!Object



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 24

def validate_credentials!
  @client..info
  true
rescue StandardError => e
  raise_provider_error(
    "DigitalOcean authentication failed",
    e,
    authentication: true,
    hint: "Use a current token for the selected team and include the account:read scope."
  )
end

#validate_server_spec!(spec:) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 36

def validate_server_spec!(spec:)
  validate_region!(spec)
  validate_size!(spec)
  validate_image!(spec)
  true
rescue Errors::ConfigurationError
  raise
rescue StandardError => e
  raise_provider_error("Unable to validate DigitalOcean server configuration", e)
end

#wait_until_ready(id:, timeout: 180) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/kitsune/kit/adapters/digitalocean_provider.rb', line 80

def wait_until_ready(id:, timeout: 180)
  deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
  loop do
    droplet = @client.droplets.find(id: id)
    record = server_record(droplet)
    return record if record.status == "active" && record.public_ip
    break if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline

    @sleeper.sleep(POLL_INTERVAL)
  end
  raise Errors::TimeoutError.new(
    "DigitalOcean server #{id} did not become ready within #{timeout} seconds",
    hint: "Inspect the Droplet in DigitalOcean before retrying."
  )
rescue Errors::Error
  raise
rescue StandardError => e
  raise_provider_error("Unable to wait for DigitalOcean server #{id}", e)
end