Commit c496fc34eae75ca6ed38645eda5aafb9fb54a757

Authored by Georg Hopp
1 parent f8a80693

Start some real code...

  1 +# Workflow for adding a LXD host
  2 +
  3 +## User input
  4 +
  5 + * A symbolic name
  6 + * The LDX host base URL
  7 + * The password for certificate addition
  8 +
  9 +## workflow
  10 +
  11 + * Check our current client key.
  12 + * Recreate client key if we find no active valid key
  13 + * This also involves deactivating the old one and activate the new one.
  14 + * Get API version of the LXD host. (unauth)
  15 + * Bail out if not supported ... currently (only 1.0 is supported)
  16 + * Get Server info / well, this might also be done in the previous task.
  17 + * If unathorized add cert with password.
  18 + * I guess thats it.
  19 +
  20 +## stored
  21 +
  22 + * The new cert eventually
  23 + * The name and url of the LXD host
  24 +
  25 +# Workflow accessing LXD host
  26 +
  27 +## input
  28 +
  29 + * The name of the LXD host
  30 +
  31 +## workflow
  32 +
  33 + * Check our current client cert.
  34 + * If close to expiration create a new one and send it to
  35 + LXD host with the old one.
  36 + * If behind expiration ask for password
  37 + * Connect to LXD host using the current active cert.
@@ -2,4 +2,8 @@ class ApplicationController < ActionController::Base @@ -2,4 +2,8 @@ class ApplicationController < ActionController::Base
2 # Prevent CSRF attacks by raising an exception. 2 # Prevent CSRF attacks by raising an exception.
3 # For APIs, you may want to use :null_session instead. 3 # For APIs, you may want to use :null_session instead.
4 protect_from_forgery with: :exception 4 protect_from_forgery with: :exception
  5 +
  6 + def check_cert
  7 + end
5 end 8 end
  9 +# vim: set et ts=2 sw=2:
@@ -2,11 +2,14 @@ class DashboardController < ApplicationController @@ -2,11 +2,14 @@ class DashboardController < ApplicationController
2 def index 2 def index
3 @lxd_host = LxdHost.find(1) 3 @lxd_host = LxdHost.find(1)
4 @cert = Certificate.find(1) 4 @cert = Certificate.find(1)
5 - @lxd = Lxd::Server.by_host @lxd_host, @cert 5 + @api = Lxd::API.get @lxd_host, @cert
  6 + @lxd_config = Lxd::Config.get @api
6 7
7 - if @lxd.auth == 'untrusted'  
8 - Lxd::Certificate.new.save(@lxd_host, @cert)  
9 - @lxd = Lxd::Server.by_host @lxd_host, @cert 8 + if @lxd_config.auth == 'untrusted'
  9 + # Here the controller has to ask for the password
  10 + cert = Lxd::Certificate.new api: @api
  11 + cert.save 'xxxxxxxxxx'
  12 + @lxd_config = Lxd::Config.get @api
10 end 13 end
11 end 14 end
12 end 15 end
@@ -3,7 +3,7 @@ require 'digest/md5' @@ -3,7 +3,7 @@ require 'digest/md5'
3 3
4 class Certificate < ActiveRecord::Base 4 class Certificate < ActiveRecord::Base
5 def key 5 def key
6 - OpenSSL::PKey::RSA.new read_attribute(:key) if read_attribute(:key) 6 + OpenSSL::PKey::EC.new read_attribute(:key) if read_attribute(:key)
7 end 7 end
8 8
9 def cert 9 def cert
@@ -11,11 +11,16 @@ class Certificate < ActiveRecord::Base @@ -11,11 +11,16 @@ class Certificate < ActiveRecord::Base
11 end 11 end
12 12
13 def key_fpr 13 def key_fpr
14 - Digest::SHA1.hexdigest(key.to_der).upcase 14 + Digest::SHA256.hexdigest(key.to_der).upcase
15 end 15 end
16 16
17 def cert_fpr 17 def cert_fpr
18 - Digest::SHA1.hexdigest(cert.to_der).upcase 18 + Digest::SHA256.hexdigest(cert.to_der).upcase
  19 + end
  20 +
  21 + private
  22 +
  23 + def _key
19 end 24 end
20 end 25 end
21 # vim: set et ts=2 sw=2: 26 # vim: set et ts=2 sw=2:
  1 +module Lxd::API
  2 + def self.get host, certificate
  3 + uri = URI.parse host.uri
  4 + con = Net::HTTP.new uri.host, uri.port
  5 + con.use_ssl = true
  6 + con.cert = OpenSSL::X509::Certificate.new certificate.cert
  7 + con.key = OpenSSL::PKey::RSA.new certificate.key
  8 + con.verify_mode = OpenSSL::SSL::VERIFY_NONE
  9 +
  10 + resp = self.call con, Net::HTTP::Get.new('/')
  11 + raise "unsupported api version" unless resp['metadata'].include? '/1.0'
  12 + Lxd::API::V1_0.new con
  13 + end
  14 +
  15 + def self.call con, req
  16 + resp = con.request req
  17 + raise "request failure: " + resp.code unless resp.code != 200
  18 + JSON.parse resp.body
  19 + end
  20 +
  21 + def initialize con
  22 + @con = con
  23 + end
  24 +
  25 + def call req
  26 + handle_response(Lxd::API.call @con, req)
  27 + end
  28 +
  29 + def get uri
  30 + call Net::HTTP::Get.new uri
  31 + end
  32 +
  33 + def put uri, data={}
  34 + request = Net::HTTP::Put.new uri
  35 + request.body = data.to_json
  36 + call request
  37 + end
  38 +
  39 + def post uri, data={}
  40 + request = Net::HTTP::Post.new uri
  41 + request.body = data.to_json
  42 + call request
  43 + end
  44 +end
  45 +# vim: set ts=2 sw=2:
  1 +class Lxd::API::V1_0
  2 + include Lxd::API
  3 +
  4 + def config
  5 + get '/1.0'
  6 + end
  7 +
  8 + def config= config={}
  9 + put '/1.0', config: config
  10 + end
  11 +
  12 + def certificates
  13 + get '/1.0/certificates'.map { |uri|
  14 + {
  15 + :uri => uri,
  16 + :cert => get(uri)
  17 + }
  18 + }
  19 + end
  20 +
  21 + def add_certificate cert={}
  22 + # TODO validate hash
  23 + post '/1.0/certificates', cert
  24 + end
  25 +
  26 + def handle_response resp
  27 + """
  28 + 100 Operation created
  29 + 101 Started
  30 + 102 Stopped
  31 + 103 Running
  32 + 104 Cancelling
  33 + 105 Pending
  34 + 106 Starting
  35 + 107 Stopping
  36 + 108 Aborting
  37 + 109 Freezing
  38 + 110 Frozen
  39 + 111 Thawed
  40 + 200 Success
  41 + 400 Failure
  42 + 401 Cancelled
  43 +
  44 +
  45 + 100 to 199: resource state (started, stopped, ready, ...)
  46 + 200 to 399: positive action result
  47 + 400 to 599: negative action result
  48 + 600 to 999: future use
  49 + """
  50 + raise "api error" if [400..500].include? resp['error_code']
  51 + resp['metadata']
  52 + end
  53 +end
  54 +# vim: set ts=2 sw=2:
1 class Lxd::Certificate 1 class Lxd::Certificate
2 include ActiveModel::Model 2 include ActiveModel::Model
3 3
4 - def save(host, certificate)  
5 - all = Array.new; 4 + attr_accessor :api, :type, :certificate, :fingerprint
6 5
7 - uri = URI.parse(host.uri + '/1.0/certificates')  
8 - http = Net::HTTP.new(uri.host, uri.port)  
9 - http.use_ssl = true  
10 - http.cert = OpenSSL::X509::Certificate.new(certificate.cert)  
11 - http.key = OpenSSL::PKey::RSA.new(certificate.key)  
12 - http.verify_mode = OpenSSL::SSL::VERIFY_NONE 6 + def self.all api
  7 + api.certificates.map { |cert|
  8 + Lxd::Certificate.new({api: api}.merge cert)
  9 + }
  10 + end
13 11
14 - request = Net::HTTP::Post.new(uri.request_uri)  
15 - request.body = {  
16 - :type => 'client',  
17 - :name => 'foo',  
18 - :password => '[where to get this from....]'  
19 - }.to_json  
20 - response = http.request(request) 12 + def add password=nil, name='lex-deeit'
  13 + data = Hash.new
  14 + data[:type] = @type if @type else 'client'
  15 + data[:name] = name
  16 + data[:password] = password if password
  17 + data[:certificate] = @certificate if @certificate
21 18
22 - response.code 19 + @api.add_certificate data
23 end 20 end
24 end 21 end
25 # vim: set ts=2 sw=2: 22 # vim: set ts=2 sw=2:
  1 +class Lxd::Config
  2 + include ActiveModel::Model
  3 +
  4 + attr_accessor :api, :api_extensions, :api_status, :api_version, :auth,
  5 + :config, :environment, :public
  6 +
  7 + def self.get api
  8 + Lxd::Config.new({api: api}.merge api.config)
  9 + end
  10 +
  11 + def save
  12 + @api.config = @config
  13 + end
  14 +end
  15 +# vim: set ts=2 sw=2:
  1 +class Lxd::Connection
  2 + attr_reader :con, :host, :port
  3 +
  4 + """
  5 + /1.0
  6 + /1.0/certificates
  7 + /1.0/certificates/<fingerprint>
  8 + /1.0/containers
  9 + /1.0/containers/<name>
  10 + /1.0/containers/<name>/exec
  11 + /1.0/containers/<name>/files
  12 + /1.0/containers/<name>/snapshots
  13 + /1.0/containers/<name>/snapshots/<name>
  14 + /1.0/containers/<name>/state
  15 + /1.0/containers/<name>/logs
  16 + /1.0/containers/<name>/logs/<logfile>
  17 + /1.0/events
  18 + /1.0/images
  19 + /1.0/images/<fingerprint>
  20 + /1.0/images/<fingerprint>/export
  21 + /1.0/images/aliases
  22 + /1.0/images/aliases/<name>
  23 + /1.0/networks
  24 + /1.0/networks/<name>
  25 + /1.0/operations
  26 + /1.0/operations/<uuid>
  27 + /1.0/operations/<uuid>/wait
  28 + /1.0/operations/<uuid>/websocket
  29 + /1.0/profiles
  30 + /1.0/profiles/<name>
  31 + """
  32 +
  33 + def initialize host, certificate
  34 + uri = URI.parse host.uri
  35 + @host = uri.host
  36 + @port = uri.port
  37 + @con = Net::HTTP.new @host, @port
  38 + @con.use_ssl = true
  39 + @con.cert = OpenSSL::X509::Certificate.new certificate.cert
  40 + @con.key = OpenSSL::PKey::EC.new certificate.key
  41 + @con.verify_mode = OpenSSL::SSL:VERIFY_NONE
  42 + end
  43 +
  44 + def call
  45 + if not @api_version
  46 + @con.request(Net::HTTP::Get.new '/')
  47 + versions
  48 + end
  49 + end
  50 +# vim: set et ts=2 sw=2:
1 -class Lxd::Server  
2 - include ActiveModel::Model  
3 -  
4 - attr_accessor :api_extensions, :api_status, :api_version, :auth, :config,  
5 - :environment, :public  
6 -  
7 - def self.by_host(host, certificate)  
8 - all = Array.new;  
9 -  
10 - uri = URI.parse(host.uri + '/1.0')  
11 - http = Net::HTTP.new(uri.host, uri.port)  
12 - http.use_ssl = true  
13 - http.cert = OpenSSL::X509::Certificate.new(certificate.cert)  
14 - http.key = OpenSSL::PKey::RSA.new(certificate.key)  
15 - http.verify_mode = OpenSSL::SSL::VERIFY_NONE  
16 -  
17 - request = Net::HTTP::Get.new(uri.request_uri)  
18 - response = http.request(request)  
19 -  
20 - Lxd::Server.new(JSON.parse(response.body)['metadata'])  
21 - end  
22 -end  
23 -# vim: set ts=2 sw=2:  
1 <h1>Dashboard#index</h1> 1 <h1>Dashboard#index</h1>
2 <p><%= @lxd_host.class %></p> 2 <p><%= @lxd_host.class %></p>
3 <p><%= @cert.class %></p> 3 <p><%= @cert.class %></p>
4 -<p><%= @lxd.class %></p>  
5 -<p><%= @lxd.api_extensions.inspect %></p>  
6 -<p><%= @lxd.api_status %></p>  
7 -<p><%= @lxd.api_version %></p>  
8 -<p><%= @lxd.auth %></p>  
9 -<p><%= @lxd.config.inspect %></p>  
10 -<p><%= @lxd.environment.inspect %></p>  
11 -<p><%= @lxd.public %></p> 4 +<p><%= @lxd_config.class %></p>
  5 +<p><%= @lxd_config.api_extensions.inspect %></p>
  6 +<p><%= @lxd_config.api_status %></p>
  7 +<p><%= @lxd_config.api_version %></p>
  8 +<p><%= @lxd_config.auth %></p>
  9 +<p><%= @lxd_config.config.inspect %></p>
  10 +<p><%= @lxd_config.environment.inspect %></p>
  11 +<p><%= @lxd_config.public %></p>
Please register or login to post a comment