Hello community,

here is the log from the commit of package velum for openSUSE:Factory checked 
in at 2018-05-11 09:18:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/velum (Old)
 and      /work/SRC/openSUSE:Factory/.velum.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "velum"

Fri May 11 09:18:05 2018 rev:26 rq:606231 
version:4.0.0+dev+git_r754_6c7835c7a3cc0999ebebf57517c32bf35bbd8bd0

Changes:
--------
--- /work/SRC/openSUSE:Factory/velum/velum.changes      2018-05-10 
15:50:51.222066861 +0200
+++ /work/SRC/openSUSE:Factory/.velum.new/velum.changes 2018-05-11 
09:18:08.490805711 +0200
@@ -1,0 +2,45 @@
+Wed May  9 18:02:44 UTC 2018 - [email protected]
+
+- Commit 9d97b1d by James Mason [email protected]
+ Prevent double-clicking setup#bootstrap submit in public cloud
+ 
+ Since that actually triggered construction of nodes, we need just a little
+ something to keep the impatient from clicking over & over.
+
+
+-------------------------------------------------------------------
+Wed May  9 17:44:25 UTC 2018 - [email protected]
+
+- Commit f24a3f1 by James Mason [email protected]
+ Include counts on cloud bootstrap jobs in discovery UI
+ 
+ Commit f50a986 by James Mason [email protected]
+ Return cloud bootstrapping job progress in discovery
+ 
+ BONUS: render discovery.html faster by not evaluating unused hash conditions.
+ 
+ Commit 1c00b7b by James Mason [email protected]
+ Move cloud cluster building into model; capture job ids...
+ 
+ ... clear failures on (re)start
+ 
+ Commit 8fcedc8 by James Mason [email protected]
+ Add an event handler for completing cloud bootstrap
+ 
+ Commit d50aad9 by James Mason [email protected]
+ Define a model for persisting salt job progress.
+
+
+-------------------------------------------------------------------
+Wed May  9 12:19:39 UTC 2018 - [email protected]
+
+- Commit 1f3adaa by Rafael Fernández López [email protected]
+ Make the `bin/init` process only do initialization operations
+ 
+ Do not make this script run the puma server. This way, this command can be
+ run as an init container, leaving the server execution to the pod definition.
+ 
+ Fixes: bsc#1091843
+
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ velum.spec ++++++
--- /var/tmp/diff_new_pack.u4HEZn/_old  2018-05-11 09:18:10.450734700 +0200
+++ /var/tmp/diff_new_pack.u4HEZn/_new  2018-05-11 09:18:10.454734555 +0200
@@ -23,7 +23,7 @@
 # Version:      1.0.0
 # %%define branch 1.0.0
 
-Version:        4.0.0+dev+git_r744_91ff022f1f12c133c9ccf131aa97bdd9091e4e50
+Version:        4.0.0+dev+git_r754_6c7835c7a3cc0999ebebf57517c32bf35bbd8bd0
 Release:        0
 %define branch master
 Summary:        Dashboard for CaasP
@@ -96,7 +96,7 @@
 %description
 velum is the dashboard for CaasP to manage and deploy kubernetes clusters on 
top of MicroOS
 
-This package has been built with commit 
91ff022f1f12c133c9ccf131aa97bdd9091e4e50 from branch master on date Wed, 09 May 
2018 07:04:56 +0000
+This package has been built with commit 
6c7835c7a3cc0999ebebf57517c32bf35bbd8bd0 from branch master on date Wed, 09 May 
2018 18:02:02 +0000
 
 %prep
 %setup -q -n velum-%{branch}

++++++ 0_set_default_salt_events_alter_time_column_value.rpm.patch ++++++
--- /var/tmp/diff_new_pack.u4HEZn/_old  2018-05-11 09:18:10.486733396 +0200
+++ /var/tmp/diff_new_pack.u4HEZn/_new  2018-05-11 09:18:10.490733251 +0200
@@ -2,7 +2,7 @@
 index b8392cd..6061543 100644
 --- a/db/schema.rb
 +++ b/db/schema.rb
-@@ -95,7 +95,7 @@ ActiveRecord::Schema.define(version: 20180406080400) do
+@@ -95,7 +95,7 @@ ActiveRecord::Schema.define(version: 20180427014552) do
    create_table "salt_events", force: :cascade do |t|
      t.string   "tag",          limit: 255,      null: false
      t.text     "data",         limit: 16777215, null: false
@@ -11,12 +11,12 @@
      t.string   "master_id",    limit: 255,      null: false
      t.datetime "taken_at"
      t.datetime "processed_at"
-@@ -113,7 +113,7 @@ ActiveRecord::Schema.define(version: 20180406080400) do
+@@ -113,7 +113,7 @@ ActiveRecord::Schema.define(version: 20180427014552) do
      t.string   "id",         limit: 255,      null: false
      t.string   "success",    limit: 10,       null: false
      t.text     "full_ret",   limit: 16777215, null: false
 -    t.datetime "alter_time",                  null: false
 +    t.column   "alter_time", "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP"
    end
- 
+
    add_index "salt_returns", ["fun"], name: "fun", using: :btree

++++++ master.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/assets/javascripts/cloud/bootstrap.js 
new/velum-master/app/assets/javascripts/cloud/bootstrap.js
--- old/velum-master/app/assets/javascripts/cloud/bootstrap.js  2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/app/assets/javascripts/cloud/bootstrap.js  2018-05-09 
20:02:40.000000000 +0200
@@ -62,4 +62,9 @@
 
   // kick things off
   $('input[name="cloud_cluster[instance_type]"][checked="checked"]').click();
+
+  // only submit once
+  $('form#new_cloud_cluster').submit(function(){
+      $(this).find('input[type=submit]').prop('disabled', true);
+  });
 });
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/assets/javascripts/dashboard/dashboard.js 
new/velum-master/app/assets/javascripts/dashboard/dashboard.js
--- old/velum-master/app/assets/javascripts/dashboard/dashboard.js      
2018-05-09 09:05:11.000000000 +0200
+++ new/velum-master/app/assets/javascripts/dashboard/dashboard.js      
2018-05-09 20:02:40.000000000 +0200
@@ -66,6 +66,8 @@
         var unassignedMinions = data.unassigned_minions || [];
         var allMinions = minions.concat(unassignedMinions);
         var pendingMinions = data.pending_minions || [];
+        var pendingCloudJobs = data.pending_cloud_jobs || 0;
+        var cloudJobsFailed = data.cloud_jobs_failed || 0;
 
         // for the dashboard, if we rely on radio, the first time this comes
         // it won't detect that there's a master, so we need to rely on the 
data
@@ -106,6 +108,34 @@
           MinionPoller.initialized = true;
         }
 
+        // handle public cloud bootstrapping alerts
+        if (pendingCloudJobs > 0) {
+            $('#discovery-pending-cloud-jobs-count').text(pendingCloudJobs);
+            if (pendingCloudJobs == 1) {
+                $('#discovery-pending-cloud-jobs 
span.singular').removeClass('hidden');
+                $('#discovery-pending-cloud-jobs 
span.plural').addClass('hidden');
+            } else {
+                $('#discovery-pending-cloud-jobs 
span.plural').removeClass('hidden');
+                $('#discovery-pending-cloud-jobs 
span.singular').addClass('hidden');
+            }
+            $('#discovery-pending-cloud-jobs').removeClass('hidden');
+        } else {
+            $('#discovery-pending-cloud-jobs').addClass('hidden');
+        }
+        if (cloudJobsFailed > 0) {
+            $('#discovery-cloud-job-errors-count').text(cloudJobsFailed);
+            if (cloudJobsFailed == 1) {
+                $('#discovery-bootstrap-alert 
span.singular').removeClass('hidden');
+                $('#discovery-bootstrap-alert span.plural').addClass('hidden');
+            } else {
+                $('#discovery-bootstrap-alert 
span.plural').removeClass('hidden');
+                $('#discovery-bootstrap-alert 
span.singular').addClass('hidden');
+            }
+            $('#discovery-bootstrap-alert').removeClass('hidden');
+        } else {
+            $('#discovery-bootstrap-alert').addClass('hidden');
+        }
+
         switch (MinionPoller.renderMode) {
         case "Discovery":
           minions = allMinions;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/controllers/concerns/discovery.rb 
new/velum-master/app/controllers/concerns/discovery.rb
--- old/velum-master/app/controllers/concerns/discovery.rb      2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/app/controllers/concerns/discovery.rb      2018-05-09 
20:02:40.000000000 +0200
@@ -7,22 +7,18 @@
 
   # Responds with either an HTML or JSON version of the available minions.
   def discovery
-    assigned_minions                  = Minion.cluster_role
-    unassigned_minions                = Minion.unassigned_role
-    pending_minions                   = ::Velum::Salt.pending_minions
-    retryable_bootstrap_orchestration = Orchestration.retryable? kind: 
:bootstrap
-    retryable_upgrade_orchestration   = Orchestration.retryable? kind: :upgrade
-
     respond_to do |format|
       format.html
       format.json do
         hsh = {
-          assigned_minions:                  assigned_minions,
-          unassigned_minions:                unassigned_minions,
-          pending_minions:                   pending_minions,
+          assigned_minions:                  Minion.cluster_role,
+          unassigned_minions:                Minion.unassigned_role,
+          pending_minions:                   ::Velum::Salt.pending_minions,
+          pending_cloud_jobs:                SaltJob.all_open.count,
+          cloud_jobs_failed:                 SaltJob.failed.count,
           admin:                             Minion.find_by(minion_id: 
"admin"),
-          retryable_bootstrap_orchestration: retryable_bootstrap_orchestration,
-          retryable_upgrade_orchestration:   retryable_upgrade_orchestration
+          retryable_bootstrap_orchestration: Orchestration.retryable?(kind: 
:bootstrap),
+          retryable_upgrade_orchestration:   Orchestration.retryable?(kind: 
:upgrade)
         }
         render json: hsh
       end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/controllers/setup_controller.rb 
new/velum-master/app/controllers/setup_controller.rb
--- old/velum-master/app/controllers/setup_controller.rb        2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/app/controllers/setup_controller.rb        2018-05-09 
20:02:40.000000000 +0200
@@ -96,7 +96,7 @@
     @cloud_cluster = CloudCluster.new(cloud_cluster_params)
 
     if @cloud_cluster.save
-      Velum::Salt.build_cloud_cluster(@cloud_cluster.instance_count)
+      @cloud_cluster.build!
       redirect_to setup_discovery_path,
         notice: "Starting to build #{@cloud_cluster}..."
     else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/models/cloud_cluster.rb 
new/velum-master/app/models/cloud_cluster.rb
--- old/velum-master/app/models/cloud_cluster.rb        2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/app/models/cloud_cluster.rb        2018-05-09 
20:02:40.000000000 +0200
@@ -52,6 +52,18 @@
     Velum::Salt.call(action: "saltutil.refresh_pillar")
   end
 
+  def build!
+    SaltJob.failed.destroy_all
+    return unless (responses = 
Velum::Salt.build_cloud_cluster(@instance_count))
+    responses.each do |response|
+      if response.code.to_i == 500
+        errors.add(:base, response.body)
+      else
+        SaltJob.create(jid: JSON.parse(response.body)["return"].first["jid"])
+      end
+    end
+  end
+
   def save
     save!
     return true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/models/salt_event.rb 
new/velum-master/app/models/salt_event.rb
--- old/velum-master/app/models/salt_event.rb   2018-05-09 09:05:11.000000000 
+0200
+++ new/velum-master/app/models/salt_event.rb   2018-05-09 20:02:40.000000000 
+0200
@@ -12,7 +12,8 @@
     SaltHandler::MinionStart,
     SaltHandler::MinionHighstate,
     SaltHandler::OrchestrationTrigger,
-    SaltHandler::OrchestrationResult
+    SaltHandler::OrchestrationResult,
+    SaltHandler::CloudBootstrap
   ].freeze
 
   scope :not_processed, -> { where(processed_at: nil) }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/models/salt_handler/cloud_bootstrap.rb 
new/velum-master/app/models/salt_handler/cloud_bootstrap.rb
--- old/velum-master/app/models/salt_handler/cloud_bootstrap.rb 1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/app/models/salt_handler/cloud_bootstrap.rb 2018-05-09 
20:02:40.000000000 +0200
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+require "velum/salt"
+
+# This class is responsible to handle the salt events with tag "minion_start".
+# When such an event occurs, we want the minion to be saved in our database
+# if not already there.
+class SaltHandler::CloudBootstrap
+  attr_reader :salt_event, :job
+
+  TAG_MATCHER = %r{^salt\/job\/(?<jid>\d+)\/ret\/admin$}
+
+  def self.can_handle_event?(event)
+    matches = TAG_MATCHER.match(event.tag)
+    return false unless matches
+    return false if event.parsed_data["fun"] != "cloud.profile"
+    SaltJob.all_open.jids.include? matches[:jid]
+  end
+
+  def initialize(salt_event)
+    @salt_event = salt_event
+    jid = TAG_MATCHER.match(@salt_event.tag)[:jid]
+    @job = SaltJob.find_by(jid: jid)
+  end
+
+  def process_event
+    parsed_data = salt_event.parsed_data
+    job.complete!(parsed_data["retcode"] || -1, master_trace: 
parsed_data["return"])
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/models/salt_job.rb 
new/velum-master/app/models/salt_job.rb
--- old/velum-master/app/models/salt_job.rb     1970-01-01 01:00:00.000000000 
+0100
+++ new/velum-master/app/models/salt_job.rb     2018-05-09 20:02:40.000000000 
+0200
@@ -0,0 +1,34 @@
+# Store selected salt job ids, and record on their result
+class SaltJob < ActiveRecord::Base
+  validates :jid, uniqueness: true
+
+  scope :all_open, -> { where(retcode: nil) }
+  scope :failed, -> { where.not(retcode: [nil, 0]) }
+  scope :jids, -> { pluck(:jid) }
+
+  def complete!(retcode = 0, master_trace: nil, minion_trace: nil)
+    changes = { retcode: retcode }
+    changes[:master_trace] = master_trace if master_trace
+    changes[:minion_trace] = minion_trace if minion_trace
+    update_attributes! changes
+
+    parse_upstream_error if failed?
+  end
+
+  def completed?
+    retcode.present?
+  end
+
+  def succeeded?
+    completed? && retcode.zero?
+  end
+
+  def failed?
+    completed? && !retcode.zero?
+  end
+
+  def parse_upstream_error
+    return if master_trace.blank? && minion_trace.blank?
+    errors.add(:base, "Please check `/var/log/salt/minion` for details.")
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/views/setup/discovery.html.slim 
new/velum-master/app/views/setup/discovery.html.slim
--- old/velum-master/app/views/setup/discovery.html.slim        2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/app/views/setup/discovery.html.slim        2018-05-09 
20:02:40.000000000 +0200
@@ -1,3 +1,25 @@
+.alert.alert-info#discovery-pending-cloud-jobs.hidden role="alert"
+  i.fa.fa-4x.pull-left aria-hidden="true"
+  span
+    | Deployment of
+    span#discovery-pending-cloud-jobs-count<>
+    | more
+    span.singular.hidden<> node is
+    span.plural.hidden<> nodes are
+    | pending...
+
+.alert.alert-danger#discovery-bootstrap-alert.hidden role="alert"
+  i.fa.fa-4x.pull-left aria-hidden="true"
+  span
+    span#discovery-cloud-job-errors-count<>
+    | node
+    span.singular.hidden<> deployment
+    span.plural.hidden<> deployments
+    | failed. Please check
+    code<>
+      | /var/log/salt/minion
+    | for details.
+
 .alert.alert-warning.discovery-minimum-nodes-alert role="alert" hidden="true"
   i.fa.fa-4x.pull-left aria-hidden="true"
   span
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/bin/init new/velum-master/bin/init
--- old/velum-master/bin/init   2018-05-09 09:05:11.000000000 +0200
+++ new/velum-master/bin/init   2018-05-09 20:02:40.000000000 +0200
@@ -1,19 +1,9 @@
 #!/bin/bash
 
-# This script will setup the database and then start the rails application
+# This script will setup the database
 
 set -e
 
-: ${VELUM_PORT:=80}
-
-setup_root_ca() {
-  # Velum is going to need this CA to talk to the running CaaSP Cluster
-  [ -f "/etc/pki/trust/anchors/SUSE_CaaSP_CA.pem" ] && return
-
-  cp /etc/pki/ca.crt /etc/pki/trust/anchors/SUSE_CaaSP_CA.pem
-  update-ca-certificates
-}
-
 setup_database() {
   set +e
 
@@ -75,8 +65,6 @@
   fi
 }
 
-setup_root_ca
 setup_database
 setup_pillar_seeds
 setup_cpi
-bundle exec "puma -C config/puma.rb"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/bin/run new/velum-master/bin/run
--- old/velum-master/bin/run    1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/bin/run    2018-05-09 20:02:40.000000000 +0200
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+setup_root_ca() {
+  # Velum is going to need this CA to talk to the running CaaSP Cluster
+  [ -f "/etc/pki/trust/anchors/SUSE_CaaSP_CA.pem" ] && return
+
+  cp /etc/pki/ca.crt /etc/pki/trust/anchors/SUSE_CaaSP_CA.pem
+  update-ca-certificates
+}
+
+setup_root_ca
+bundle exec "puma -C config/puma.rb"
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/db/migrate/20180427014552_create_salt_jobs.rb 
new/velum-master/db/migrate/20180427014552_create_salt_jobs.rb
--- old/velum-master/db/migrate/20180427014552_create_salt_jobs.rb      
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/db/migrate/20180427014552_create_salt_jobs.rb      
2018-05-09 20:02:40.000000000 +0200
@@ -0,0 +1,13 @@
+class CreateSaltJobs < ActiveRecord::Migration
+  def change
+    create_table :salt_jobs do |t|
+      t.string :jid
+      t.integer :retcode
+      t.text :master_trace
+      t.text :minion_trace
+
+      t.timestamps null: false
+    end
+    add_index :salt_jobs, :jid
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/db/schema.rb 
new/velum-master/db/schema.rb
--- old/velum-master/db/schema.rb       2018-05-09 09:05:11.000000000 +0200
+++ new/velum-master/db/schema.rb       2018-05-09 20:02:40.000000000 +0200
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control 
system.
 
-ActiveRecord::Schema.define(version: 20180406080400) do
+ActiveRecord::Schema.define(version: 20180427014552) do
 
   create_table "certificate_services", force: :cascade do |t|
     t.integer  "certificate_id", limit: 4
@@ -106,6 +106,17 @@
   add_index "salt_events", ["tag"], name: "tag", using: :btree
   add_index "salt_events", ["worker_id", "taken_at"], name: 
"index_salt_events_on_worker_id_and_taken_at", using: :btree
 
+  create_table "salt_jobs", force: :cascade do |t|
+    t.string   "jid",          limit: 255
+    t.integer  "retcode",      limit: 4
+    t.text     "master_trace", limit: 65535
+    t.text     "minion_trace", limit: 65535
+    t.datetime "created_at",                 null: false
+    t.datetime "updated_at",                 null: false
+  end
+
+  add_index "salt_jobs", ["jid"], name: "index_salt_jobs_on_jid", using: :btree
+
   create_table "salt_returns", id: false, force: :cascade do |t|
     t.string   "fun",        limit: 50,       null: false
     t.string   "jid",        limit: 255,      null: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/packaging/suse/patches/0_set_default_salt_events_alter_time_column_value.rpm.patch
 
new/velum-master/packaging/suse/patches/0_set_default_salt_events_alter_time_column_value.rpm.patch
--- 
old/velum-master/packaging/suse/patches/0_set_default_salt_events_alter_time_column_value.rpm.patch
 2018-05-09 09:05:11.000000000 +0200
+++ 
new/velum-master/packaging/suse/patches/0_set_default_salt_events_alter_time_column_value.rpm.patch
 2018-05-09 20:02:40.000000000 +0200
@@ -2,7 +2,7 @@
 index b8392cd..6061543 100644
 --- a/db/schema.rb
 +++ b/db/schema.rb
-@@ -95,7 +95,7 @@ ActiveRecord::Schema.define(version: 20180406080400) do
+@@ -95,7 +95,7 @@ ActiveRecord::Schema.define(version: 20180427014552) do
    create_table "salt_events", force: :cascade do |t|
      t.string   "tag",          limit: 255,      null: false
      t.text     "data",         limit: 16777215, null: false
@@ -11,12 +11,12 @@
      t.string   "master_id",    limit: 255,      null: false
      t.datetime "taken_at"
      t.datetime "processed_at"
-@@ -113,7 +113,7 @@ ActiveRecord::Schema.define(version: 20180406080400) do
+@@ -113,7 +113,7 @@ ActiveRecord::Schema.define(version: 20180427014552) do
      t.string   "id",         limit: 255,      null: false
      t.string   "success",    limit: 10,       null: false
      t.text     "full_ret",   limit: 16777215, null: false
 -    t.datetime "alter_time",                  null: false
 +    t.column   "alter_time", "DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP"
    end
- 
+
    add_index "salt_returns", ["fun"], name: "fun", using: :btree
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/controllers/setup_controller_spec.rb 
new/velum-master/spec/controllers/setup_controller_spec.rb
--- old/velum-master/spec/controllers/setup_controller_spec.rb  2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/spec/controllers/setup_controller_spec.rb  2018-05-09 
20:02:40.000000000 +0200
@@ -674,6 +674,25 @@
       get :discovery
       expect(response.status).to eq 200
     end
+
+    describe "as JSON" do
+      let(:pending) { 3 }
+      let(:failed) { 1 }
+
+      before do
+        pending.times { FactoryGirl.create(:salt_job) }
+        failed.times { FactoryGirl.create(:salt_job_failed) }
+        get :discovery, format: :json
+      end
+
+      it "includes a count of incomplete cloud jobs" do
+        expect(JSON.parse(response.body)["pending_cloud_jobs"]).to eq(pending)
+      end
+
+      it "includes a count of failed cloud jobs" do
+        expect(JSON.parse(response.body)["cloud_jobs_failed"]).to eq(failed)
+      end
+    end
   end
 
   describe "POST /setup/bootstrap" do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/factories/salt_job_factory.rb 
new/velum-master/spec/factories/salt_job_factory.rb
--- old/velum-master/spec/factories/salt_job_factory.rb 1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/factories/salt_job_factory.rb 2018-05-09 
20:02:40.000000000 +0200
@@ -0,0 +1,10 @@
+FactoryGirl.define do
+  factory :salt_job do
+    jid { Time.current.strftime("%Y%m%d%H%M%S%6NS") }
+
+    factory :salt_job_failed do
+      retcode 1
+      master_trace { FFaker::Lorem.sentence }
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/features/bootstrap_cluster_feature_spec.rb 
new/velum-master/spec/features/bootstrap_cluster_feature_spec.rb
--- old/velum-master/spec/features/bootstrap_cluster_feature_spec.rb    
2018-05-09 09:05:11.000000000 +0200
+++ new/velum-master/spec/features/bootstrap_cluster_feature_spec.rb    
2018-05-09 20:02:40.000000000 +0200
@@ -20,11 +20,24 @@
                       { minion_id: SecureRandom.hex, fqdn: "minion4.k8s.local" 
}]
     end
 
+    let(:pending) { 5 }
+    let(:failed) { 2 }
+
     before do
+      pending.times { FactoryGirl.create(:salt_job) }
+      failed.times { FactoryGirl.create(:salt_job_failed) }
       allow_any_instance_of(Velum::SaltMinion).to 
receive(:assign_role).and_return(true)
       allow(Orchestration).to receive(:run)
     end
 
+    it "Includes a count of pending cloud jobs", js: true do
+      expect(page).to have_content("Deployment of #{pending} more nodes are 
pending...")
+    end
+
+    it "Include a notice of failed cloud jobs", js: true do
+      expect(page).to have_content("#{failed} node deployments failed.")
+    end
+
     it "A user sees warning modal when trying to bootstrap 2 nodes", js: true 
do
       # select master minion0.k8s.local
       find(".minion_#{minions[0].id} .master-btn").click
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/models/cloud_cluster_spec.rb 
new/velum-master/spec/models/cloud_cluster_spec.rb
--- old/velum-master/spec/models/cloud_cluster_spec.rb  2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/spec/models/cloud_cluster_spec.rb  2018-05-09 
20:02:40.000000000 +0200
@@ -218,4 +218,50 @@
       expect(cluster.to_s).to match(substring)
     end
   end
+
+  context "when building" do
+    let(:cluster) do
+      described_class.new(
+        instance_type:     custom_instance_type,
+        instance_count:    instance_count,
+        resource_group:    resource_group,
+        network_id:        network_id,
+        subnet_id:         subnet_id,
+        security_group_id: security_group_id
+      )
+    end
+    let(:error_message) { "[\"Nope!\"]" }
+
+    it "captures jobs" do
+      VCR.use_cassette("salt/cloud_profile", record: :none, 
allow_playback_repeats: true) do
+        cluster.save!
+        cluster.build!
+        expect(SaltJob.all_open.count).to eq(instance_count)
+      end
+    end
+
+    it "captures errors" do
+      VCR.use_cassette("salt/login_500", record: :none, 
allow_playback_repeats: true) do
+        cluster.save!
+        cluster.build!
+        expect(cluster.errors[:base]).to include(error_message)
+      end
+    end
+
+    context "with prior failed jobs" do
+      let(:failures) { 3 }
+
+      before do
+        failures.times { FactoryGirl.create(:salt_job_failed) }
+      end
+
+      it "clears failed jobs when (re)starting" do
+        VCR.use_cassette("salt/cloud_profile", record: :none, 
allow_playback_repeats: true) do
+          cluster.save!
+          cluster.build!
+          expect(SaltJob.failed.count).to be_zero
+        end
+      end
+    end
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/models/salt_handler/cloud_bootstrap_spec.rb 
new/velum-master/spec/models/salt_handler/cloud_bootstrap_spec.rb
--- old/velum-master/spec/models/salt_handler/cloud_bootstrap_spec.rb   
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/spec/models/salt_handler/cloud_bootstrap_spec.rb   
2018-05-09 20:02:40.000000000 +0200
@@ -0,0 +1,213 @@
+require "rails_helper"
+
+describe SaltHandler::CloudBootstrap do
+  let!(:jid) { Time.current.strftime("%Y%m%d%H%M%S%6N") }
+  let(:node_id) { "caasp-node-" + SecureRandom.hex(8) }
+  let(:ip) { FFaker::Internet.ip_v4_address }
+  let(:instance_id) { "i-" + SecureRandom.hex(17) }
+  let!(:job) { FactoryGirl.create(:salt_job, jid: jid) }
+  let(:salt_event) do
+    event_data = {
+      "fun_args" => ["cluster_node", node_id],
+      "jid"      => jid,
+      "return"   => {
+        node_id => {
+          "productCodes"        => nil,
+          "vpcId"               => "vpc-" + SecureRandom.hex(8),
+          "instanceId"          => instance_id,
+          "image"               => "ami-" + SecureRandom.hex(8),
+          "imageId"             => "ami-" + SecureRandom.hex(8),
+          "keyName"             => "caasp-ip-" + ip.tr(".", "-"),
+          "clientToken"         => nil,
+          "subnetId"            => "subnet-" + SecureRandom.hex(8),
+          "amiLaunchIndex"      => "0",
+          "instanceType"        => "t2.xlarge",
+          "size"                => "t2.xlarge",
+          "groupSet"            => {
+            "item" => {
+              "groupName" => "caasp-ip-" + ip.tr(".", "-"),
+              "groupId"   => "sg-" + SecureRandom.hex(8)
+            }
+          },
+          "monitoring"          => { "state" => "disabled" },
+          "id"                  => instance_id,
+          "state"               => "running",
+          "dnsName"             => nil,
+          "privateIpAddress"    => ip,
+          "virtualizationType"  => "hvm",
+          "privateDnsName"      => "ip-" + ip.tr(".", "-") + 
".us-west-2.compute.internal",
+          "reason"              => nil,
+          "tagSet"              => {
+            "item" => { "key" => "Name", "value" => node_id }
+          },
+          "deployed"            => true,
+          "private_ips"         => ip,
+          "sourceDestCheck"     => "true",
+          "blockDeviceMapping"  => {
+            "item" => {
+              "deviceName" => "/dev/sda1",
+              "ebs"        => {
+                "status"              => "attached",
+                "deleteOnTermination" => "true",
+                "volumeId"            => "vol-" + SecureRandom.hex(17),
+                "attachTime"          => FFaker::Time.datetime
+              }
+            }
+          },
+          "placement"           => {
+            "groupName"        => nil,
+            "tenancy"          => "default",
+            "availabilityZone" => "us-west-2c"
+          },
+          "name"                => node_id,
+          "instanceState"       => { "code" => "16", "name" => "running" },
+          "networkInterfaceSet" => {
+            "item" => {
+              "status"                => "in-use",
+              "macAddress"            => FFaker::Internet.mac,
+              "sourceDestCheck"       => "true",
+              "vpcId"                 => "vpc-" + SecureRandom.hex(8),
+              "description"           => nil,
+              "networkInterfaceId"    => "eni-" + SecureRandom.hex(8),
+              "privateIpAddress"      => ip,
+              "groupSet"              => {
+                "item" => {
+                  "groupName" => "caasp-ip-" + ip.tr(".", "-"),
+                  "groupId"   => "sg-" + SecureRandom.hex(8)
+                }
+              },
+              "attachment"            => {
+                "status"              => "attached",
+                "deviceIndex"         => "0",
+                "deleteOnTermination" => "true",
+                "attachmentId"        => "eni-attach-" + SecureRandom.hex(8),
+                "attachTime"          => FFaker::Time.datetime
+              },
+              "subnetId"              => "subnet-" + SecureRandom.hex(8),
+              "ownerId"               => FFaker::PhoneNumber.imei,
+              "privateIpAddressesSet" => {
+                "item" => {
+                  "privateIpAddress" => ip,
+                  "primary"          => "true",
+                  "association"      => {
+                    "publicIp"      => FFaker::Internet.ip_v4_address,
+                    "publicDnsName" => nil,
+                    "ipOwnerId"     => "amazon"
+                  }
+                }
+              },
+              "association"           => {
+                "publicIp"      => FFaker::Internet.ip_v4_address,
+                "publicDnsName" => nil,
+                "ipOwnerId"     => "amazon"
+              }
+            }
+          },
+          "public_ips"          => FFaker::Internet.ip_v4_address,
+          "ebsOptimized"        => "false",
+          "launchTime"          => FFaker::Time.datetime,
+          "architecture"        => "x86_64",
+          "hypervisor"          => "xen",
+          "rootDeviceType"      => "ebs",
+          "ipAddress"           => FFaker::Internet.ip_v4_address,
+          "rootDeviceName"      => "/dev/sda1"
+        }
+      },
+      "retcode"  => 0,
+      "success"  => true,
+      "cmd"      => "_return",
+      "_stamp"   => FFaker::Time.datetime,
+      "fun"      => "cloud.profile",
+      "id"       => "admin"
+    }.to_json
+
+    FactoryGirl.create(:salt_event,
+      tag:  "salt/job/" + jid + "/ret/admin",
+      data: event_data)
+  end
+
+  let(:failed_salt_event) do
+    return_string = <<-RETURN
+      The minion function caused an exception: Traceback (most recent call 
last):
+      File "/usr/lib/python2.7/site-packages/salt/minion.py", line 1455, in 
_thread_return
+      return_data = executor.execute()
+      File "/usr/lib/python2.7/site-packages/salt/executors/direct_call.py", 
line 28, in execute
+      return self.func(*self.args, **self.kwargs)
+      File "/usr/lib/python2.7/site-packages/salt/modules/cloud.py", line 199, 
in profile_
+      info = client.profile(profile, names, vm_overrides=vm_overrides, 
**kwargs)
+      File "/usr/lib/python2.7/site-packages/salt/cloud/__init__.py", line 
352, in profile   mapper.run_profile(profile, names, vm_overrides=vm_overrides)
+      File "/usr/lib/python2.7/site-packages/salt/cloud/__init__.py", line 
1465, in run_profile
+      raise SaltCloudSystemExit('Failed to deploy VM')
+      SaltCloudSystemExit: Failed to deploy VM
+    RETURN
+
+    event_data = {
+      "fun_args" => ["cluster_node", node_id],
+      "jid"      => "20180501164423788496",
+      "return"   => return_string,
+      "success"  => false,
+      "cmd"      => "_return",
+      "_stamp"   => FFaker::Time.datetime,
+      "fun"      => "cloud.profile",
+      "id"       => "admin",
+      "out"      => "nested"
+    }.to_json
+
+    FactoryGirl.create(:salt_event,
+      tag:  "salt/job/" + jid + "/ret/admin",
+      data: event_data)
+  end
+
+  describe "when handling events" do
+    let(:random_event) do
+      FactoryGirl.create(:salt_event,
+        tag:  "salt/job/" + jid + "/ret/" + jid,
+        data: {}.to_json)
+    end
+    let(:admin_other_event) do
+      FactoryGirl.create(:salt_event,
+        tag:  "salt/job/" + jid + "/ret/admin",
+        data: { "fun" => "foo.bar" }.to_json)
+    end
+    let(:untracked_event) do
+      FactoryGirl.create(:salt_event,
+        tag:  "salt/job/1/ret/admin",
+        data: { "fun" => "cloud.profile" }.to_json)
+    end
+
+    it "returns false if job was not run on admin node" do
+      expect(described_class).not_to be_can_handle_event(random_event)
+    end
+
+    it "returns false if job is not using 'cloud.profile' function" do
+      expect(described_class).not_to be_can_handle_event(admin_other_event)
+    end
+
+    it "returns failse if job id is not tracked" do
+      expect(described_class).not_to be_can_handle_event(untracked_event)
+    end
+
+    it "returns true if admin node job, 'cloud.profile' function, tracked job 
id" do
+      expect(described_class).to be_can_handle_event(salt_event)
+    end
+  end
+
+  describe "when processing events" do
+    let(:handler) { described_class.new(salt_event) }
+    let(:failed_handler) { described_class.new(failed_salt_event) }
+
+    it "updates the job on a successful event" do
+      handler.process_event
+      job.reload
+      expect(job).to be_completed
+      expect(job).to be_succeeded
+    end
+
+    it "updates the job on a failed event" do
+      failed_handler.process_event
+      job.reload
+      expect(job).to be_completed
+      expect(job).to be_failed
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/models/salt_job_spec.rb 
new/velum-master/spec/models/salt_job_spec.rb
--- old/velum-master/spec/models/salt_job_spec.rb       1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/models/salt_job_spec.rb       2018-05-09 
20:02:40.000000000 +0200
@@ -0,0 +1,104 @@
+require "rails_helper"
+
+describe SaltJob do
+  it { is_expected.to validate_uniqueness_of(:jid) }
+
+  context "when a job is completed" do
+    it "defaults to falsey" do
+      expect(described_class.new).not_to be_completed
+    end
+
+    it "can be set by an action" do
+      job = described_class.new
+      job.complete!
+      expect(job).to be_completed
+    end
+  end
+
+  context "when storing the job return code" do
+    it "defaults to success" do
+      job = described_class.new
+      job.complete!
+      expect(job.retcode).to eq(0)
+    end
+
+    it "can be set for success during completion" do
+      job = described_class.new
+      job.complete!(0)
+      expect(job.retcode).to eq(0)
+    end
+
+    it "can be set for failure" do
+      job = described_class.new
+      job.complete!(1)
+      expect(job.retcode).to eq(1)
+    end
+
+    it "informs success" do
+      job = described_class.new
+      job.complete!(0)
+      expect(job).to be_succeeded
+    end
+
+    it "informs against failure" do
+      job = described_class.new
+      job.complete!(0)
+      expect(job).not_to be_failed
+    end
+
+    it "informs failure" do
+      job = described_class.new
+      job.complete!(1)
+      expect(job).to be_failed
+    end
+
+    it "informs against success" do
+      job = described_class.new
+      job.complete!(1)
+      expect(job).not_to be_succeeded
+    end
+  end
+
+  context "when storing error traces" do
+    let(:master_trace) { FFaker::Lorem.paragraph }
+    let(:minion_trace) { FFaker::Lorem.paragraph }
+
+    it "is empty on success" do
+      job = described_class.new
+      job.complete!
+      expect(job.master_trace).to be_nil
+      expect(job.minion_trace).to be_nil
+    end
+
+    it "set when the job is completed" do
+      job = described_class.new
+      job.complete!(1, master_trace: master_trace, minion_trace: minion_trace)
+      expect(job.master_trace).to eq(master_trace)
+      expect(job.minion_trace).to eq(minion_trace)
+    end
+
+    context "when evaluating the error trace" do
+      let(:jid) { Time.current.strftime("%Y%m%d%H%M%S%6N") }
+      let(:log_reference_msg) do
+        "Please check `/var/log/salt/minion` for details."
+      end
+      let(:upstream_error_msg) do
+        "InstanceLimitExceeded: "\
+        "Your quota allows for 0 more running instance(s). "\
+        "You requested at least 1"
+      end
+
+      it "points at the logs with only a master trace" do
+        job = described_class.new(jid: jid)
+        job.complete!(1, master_trace: master_trace)
+        expect(job.errors[:base]).to include(log_reference_msg)
+      end
+
+      # it "provides an upstream error with a minion trace" do
+      #   job = described_class.new(jid: jid)
+      #   job.complete!(1, minion_trace: minion_trace)
+      #   expect(job.errors[:base]).to include(upstream_error_msg)
+      # end
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml 
new/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml
--- old/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml  2018-05-09 
09:05:11.000000000 +0200
+++ new/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml  2018-05-09 
20:02:40.000000000 +0200
@@ -101,7 +101,267 @@
         06:57:34 GMT; Path=/
     body:
       encoding: UTF-8
-      string: '{"return": [{"jid": "20180205205734878026", "minions": 
["admin"]}]}'
+      string: '{"return": [{"jid": "20180501142133027777", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180501142133027836", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180501142133027856", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180501142133027871", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180501142133027885", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180501142133027976", "minions": 
["admin"]}]}'
     http_version:
   recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
 recorded_with: VCR 3.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/vcr_cassettes/salt/login_500.yml 
new/velum-master/spec/vcr_cassettes/salt/login_500.yml
--- old/velum-master/spec/vcr_cassettes/salt/login_500.yml      1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/vcr_cassettes/salt/login_500.yml      2018-05-09 
20:02:40.000000000 +0200
@@ -0,0 +1,103 @@
+---
+http_interactions:
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/login
+    body:
+      encoding: UTF-8
+      string: 
'{"username":"saltapi","password":"l+ZtDm9lG1DPdt/QyFfABgWtCN/IKwnmGTK8nCt++PiOVG9Y2NccIrozchvz7RtxREIZe5CshcO0","eauth":"pam"}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+  response:
+    status:
+      code: 500
+      message: Internal Server Error
+    headers:
+      Content-Length:
+      - 9
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '["Nope!"]'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"username":"saltapi","password":"l+ZtDm9lG1DPdt/QyFfABgWtCN/IKwnmGTK8nCt++PiOVG9Y2NccIrozchvz7RtxREIZe5CshcO0","eauth":"pam"}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+  response:
+    status:
+      code: 500
+      message: Internal Server Error
+    headers:
+      Content-Length:
+      - 9
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '["Nope!"]'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+recorded_with: VCR 3.0.3


Reply via email to