class Cyclid::API::Plugins::Lxd

LXD builder. Uses the LXD REST API to create a build host container.

Public Class Methods

new() click to toggle source
# File lib/cyclid/plugins/builder/lxd.rb, line 35
def initialize
  @config = load_lxd_config(Cyclid.config.plugins)
  @client = Hyperkit::Client.new(api_endpoint: @config[:api],
                                 verify_ssl: @config[:verify_ssl],
                                 client_cert: @config[:client_cert],
                                 client_key: @config[:client_key])
end

Public Instance Methods

get(args = {}) click to toggle source

Create & return a build host

# File lib/cyclid/plugins/builder/lxd.rb, line 44
def get(args = {})
  args.symbolize_keys!

  Cyclid.logger.debug "lxd: args=#{args}"

  # If there is one, split the 'os' into a 'distro' and 'release'
  if args.key? :os
    match = args[:os].match(/\A(\w*)_(.*)\Z/)
    distro = match[1] if match
    release = match[2] if match
  else
    # No OS was specified; use the default
    # XXX Defaults should be configurable
    distro = 'ubuntu'
    release = 'trusty'
  end

  # Find the template fingerprint for the given distribution & release
  image_alias = "#{distro}/#{release}"
  fingerprint = find_or_create_image(image_alias)
  Cyclid.logger.debug "fingerprint=#{fingerprint}"

  # Create a new instance
  name = create_name
  create_container(name, fingerprint)

  # Wait for the instance to settle
  sleep 5

  # Create a buildhost from the container details
  buildhost = LxdHost.new(host: name,
                          name: name,
                          username: 'root',
                          workspace: '/root',
                          distro: distro,
                          release: release)

  buildhost
end
release(_transport, buildhost) click to toggle source

Destroy the build host

# File lib/cyclid/plugins/builder/lxd.rb, line 85
def release(_transport, buildhost)
  name = buildhost[:host]

  @client.stop_container(name)
  wait_for_container(name, 'Stopped')

  @client.delete_container(name)
rescue StandardError => ex
  Cyclid.logger.error "LXD destroy timed out: #{ex}"
end

Private Instance Methods

create_container(name, fingerprint) click to toggle source
# File lib/cyclid/plugins/builder/lxd.rb, line 149
def create_container(name, fingerprint)
  Cyclid.logger.debug "Creating container #{name}"
  @client.create_container(name, fingerprint: fingerprint)
  @client.start_container(name)

  wait_for_container(name, 'Running')
end
create_name() click to toggle source
# File lib/cyclid/plugins/builder/lxd.rb, line 166
def create_name
  base = @config[:instance_name]
  "#{base}-#{SecureRandom.hex(16)}"
end
find_or_create_image(image_alias) click to toggle source
# File lib/cyclid/plugins/builder/lxd.rb, line 128
def find_or_create_image(image_alias)
  Cyclid.logger.debug "Create image #{image_alias}"
  fingerprint = ''
  begin
    image = @client.image_by_alias(image_alias)
    Cyclid.logger.debug "found image=#{image.inspect}"
    fingerprint = image.fingerprint
  rescue Hyperkit::NotFound
    Cyclid.logger.debug "Downloading image for #{image_alias}"
    image = @client.create_image_from_remote(@config[:image_server],
                                             alias: image_alias,
                                             protocol: 'simplestreams')

    Cyclid.logger.debug "created image=#{image.inspect}"
    fingerprint = image.metadata.fingerprint
    @client.create_image_alias(fingerprint, image_alias)
  end

  fingerprint
end
load_lxd_config(config) click to toggle source

Load the config for the LXD Builder plugin and set defaults if they're not in the config

# File lib/cyclid/plugins/builder/lxd.rb, line 103
def load_lxd_config(config)
  config.symbolize_keys!

  lxd_config = config[:lxd] || {}
  lxd_config.symbolize_keys!
  Cyclid.logger.debug "config=#{lxd_config}"

  raise 'the LXD API URL must be provided' \
    unless lxd_config.key? :api

  lxd_config[:client_cert] = File.join(%w[/ etc cyclid lxd_client.crt]) \
    unless lxd_config.key? :client_cert
  lxd_config[:client_key] = File.join(%w[/ etc cyclid lxd_client.key]) \
    unless lxd_config.key? :client_key

  lxd_config[:verify_ssl] = false \
    unless lxd_config.key? :verify_ssl
  lxd_config[:image_server] = 'https://images.linuxcontainers.org:8443' \
    unless lxd_config.key? :image_server
  lxd_config[:instance_name] = 'cyclid-build' \
    unless lxd_config.key? :instance_name

  lxd_config
end
wait_for_container(name, state) click to toggle source
# File lib/cyclid/plugins/builder/lxd.rb, line 157
def wait_for_container(name, state)
  29.times.each do |_t|
    status = @client.container(name).status
    break if status == state
    Cyclid.logger.debug status
    sleep 2
  end
end