Class: Miasma::Models::Compute::Lxd

Inherits:
Miasma::Models::Compute show all
Includes:
Contrib::Lxd::Api
Defined in:
lib/miasma/contrib/lxd/compute.rb

Overview

LXD compute API

Constant Summary collapse

SERVER_STATE_MAP =

State mapping based on status

Smash.new(
  'running' => :running,
  'stopped' => :stopped
)
DEFAULT_EXEC_TIMEOUT =

Returns:

  • (Integer)
30

Constants included from Contrib::Lxd::Api

Contrib::Lxd::Api::DEFAULT_API_VERSION

Instance Method Summary collapse

Methods included from Contrib::Lxd::Api

#custom_setup, #endpoint, included, #make_request

Instance Method Details

#server_allArray<Miasma::Models::Compute::Server>

Return all servers

Returns:

  • (Array<Miasma::Models::Compute::Server>)


140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/miasma/contrib/lxd/compute.rb', line 140

def server_all
  result = request(
    :path => 'containers'
  ).get(:body)
  result.fetch(:metadata, []).map do |c_info|
    c_name = c_info.sub("/#{version}/containers/", '')
    Server.new(
      self,
      :id => c_name,
      :name => c_name
    ).valid_state
  end
end

#server_destroy(server) ⇒ TrueClass, FalseClass

Destroy an existing server

Parameters:

  • server (Miasma::Models::Compute::Server)

Returns:

  • (TrueClass, FalseClass)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/miasma/contrib/lxd/compute.rb', line 69

def server_destroy(server)
  if(server.persisted?)
    if(server.state == :running)
      result = request(
        :path => "containers/#{server.id}/state",
        :method => :put,
        :expects => 202,
        :json => {
          :action => :stop,
          :force => true
        }
      )
      wait_for_operation(result.get(:body, :operation))
    end
    request(
      :path => "containers/#{server.id}",
      :method => :delete,
      :expects => 202
    )
    true
  else
    false
  end
end

#server_execute(server, command, options = {}) ⇒ TrueClass, ...

Execute command

Parameters:

  • server (Miasma::Models::Compute::Server)
  • command (String)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :stream (IO)

    write command output

  • :return_exit_code (Integer)
  • :timeout (Integer)

Returns:

  • (TrueClass, FalseClass, Integer)

    command was successful



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
# File 'lib/miasma/contrib/lxd/compute.rb', line 202

def server_execute(server, command, options={})
  result = request(
    :method => :post,
    :path => "containers/#{server.id}/exec",
    :expects => 202,
    :json => Smash.new(
      :command => Shellwords.shellwords(command),
      :interactive => true,
      'wait-for-websocket' => true,
      :environment => options.fetch(:environment, {})
    )
  )
  dest = URI.parse(api_endpoint)
  operation = result.get(:body, :operation).sub("/#{version}/operations/", '')
  ws_common = Smash.new(
    :ssl_key => ssl_key,
    :ssl_certificate => ssl_certificate
  )
  if(options[:stream])
    ws_common[:on_message] = proc{|message|
      options[:stream].write(message)
    }
  end
  websockets = Smash[
    ['control', '0'].map do |fd_id|
      fd_secret = result.get(:body, :metadata, :fds, fd_id)
      [
        fd_id,
        Bogo::Websocket::Client.new(
          ws_common.merge(
            :destination => "wss://#{[dest.host, dest.port].compact.join(':')}",
            :path => "/#{version}/operations/#{operation}/websocket",
            :params => {
              :secret => fd_secret
            }
          )
        )
      ]
    end
  ]
  wait_for_operation(operation, options.fetch(:timeout, DEFAULT_EXEC_TIMEOUT))
  websockets.map(&:last).map(&:close)
  result = request(
    :path => "operations/#{operation}"
  )
  if(options[:return_exit_code])
    result.get(:body, :metadata, :metadata, :return)
  else
    result.get(:body, :metadata, :metadata, :return) == 0
  end
end

#server_get_file(server, path) ⇒ IO-ish

Fetch file from server

Parameters:

  • server (Miasma::Models::Compute::Server)
  • path (String)

    remote path

Returns:

  • (IO-ish)


159
160
161
162
163
164
165
166
167
# File 'lib/miasma/contrib/lxd/compute.rb', line 159

def server_get_file(server, path)
  request(
    :path => "containers/#{server.id}/files",
    :params => {
      :path => path
    },
    :disable_body_extraction => true
  ).get(:body)
end

#server_put_file(server, io, remote_path, options = {}) ⇒ TrueClass

Put file on server

Parameters:

  • server (Miasma::Models::Compute::Server)
  • io (IO-ish)
  • remote_path (String)

Returns:

  • (TrueClass)


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/miasma/contrib/lxd/compute.rb', line 175

def server_put_file(server, io, remote_path, options={})
  request(
    :method => :post,
    :path => "containers/#{server.id}/files",
    :params => {
      :path => remote_path
    },
    :body => io,
    :headers => {
      'Transfer-Encoding' => 'chunked',
      'X-LXD-uid' => options.fetch(:uid, 0),
      'X-LXD-gid' => options.fetch(:gid, 0),
      'X-LXD-mode' => options.fetch(:mode, 0700)
    }
  )
  true
end

#server_reload(server) ⇒ Miasma::Models::Compute::Server

Reload a server model’s data

Parameters:

  • server (Miasma::Models::Compute::Server)

Returns:

  • (Miasma::Models::Compute::Server)


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
# File 'lib/miasma/contrib/lxd/compute.rb', line 26

def server_reload(server)
  result = request(
    :path => "containers/#{server.id}",
    :expects => [200, 404]
  )
  if(result[:response].code == 200)
    result = result.get(:body, :metadata)
    server.load_data(
      :id => result[:name],
      :name => result[:name],
      :state => SERVER_STATE_MAP.fetch(result.get(:status, :status).downcase, :pending),
      :status => result.fetch(:status, :status, 'unknown').downcase,
      :addresses_private => (result.get(:status, :ips) || []).map{ |ip|
        Server::Address.new(
          :version => ip[:protocol].downcase.sub('ipv', '').to_i,
          :address => ip[:address]
        )
      },
      :image_id => 'unknown',
      :flavor_id => result.get(:profiles).first,
      :userdata => result.get(:userdata),
      :custom => Smash.new(
        :ephemeral => result[:ephemeral]
      )
    )
  else
    server.load_data(
      :id => server.id,
      :name => server.name,
      :state => :terminated,
      :status => 'terminated',
      :addresses_private => [],
      :image_id => 'none',
      :flavor_id => 'none'
    )
  end
  server.valid_state
end

#server_save(server) ⇒ Miasma::Models::Compute::Server

Save the server (create or update)

Parameters:

  • server (Miasma::Models::Compute::Server)

Returns:

  • (Miasma::Models::Compute::Server)


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
# File 'lib/miasma/contrib/lxd/compute.rb', line 98

def server_save(server)
  if(server.persisted?)
  else
    result = request(
      :path => 'containers',
      :method => :post,
      :expects => 202,
      :json => {
        :name => server.name,
        :profiles => [server.flavor_id],
        :ephemeral => server.custom.fetch(:ephemeral, false),
        :source => {
          :type => :image,
          :alias => server.image_id
        }
      }
    )
    wait_for_operation(result.get(:body, :operation), 60)
    server.id = server.name
    server.reload
    until(server.state == :running || server.state == :terminated)
      request(
        :path => "containers/#{server.name}/state",
        :method => :put,
        :expects => 202,
        :json => {
          :action => :start
        }
      )
      wait_for_operation(result.get(:body, :operation), 60)
      server.reload
    end
    if(server.state == :terminated)
      raise "Failed to save server state! (`#{server.name}`)"
    end
    server
  end
end