From: Jan Provaznik <jprovazn(a)redhat.com>
https://www.aeolusproject.org/redmine/issues/3160
---
src/app/models/deployment.rb | 40 +++++++++++++++++-
src/app/models/instance.rb | 4 ++
src/app/models/instance_observer.rb | 1 +
src/spec/models/deployment_spec.rb | 81 ++++++++++++++++++++++++++++++-----
4 files changed, 114 insertions(+), 12 deletions(-)
diff --git a/src/app/models/deployment.rb b/src/app/models/deployment.rb
index 3347367..fe8008a 100644
--- a/src/app/models/deployment.rb
+++ b/src/app/models/deployment.rb
@@ -76,11 +76,11 @@ class Deployment < ActiveRecord::Base
before_create :set_new_state
USER_MUTABLE_ATTRS = ['name']
- STATE_MIXED = "mixed"
STATE_NEW = "new"
STATE_PENDING = "pending"
STATE_RUNNING = "running"
+ STATE_INCOMPLETE = "incomplete"
STATE_SHUTTING_DOWN = "shutting_down"
STATE_STOPPED = "stopped"
STATE_FAILED = "failed"
@@ -450,6 +450,17 @@ class Deployment < ActiveRecord::Base
instances.select {|instance| instance.failed?}
end
+ def update_state(changed_instance)
+ transition_method = "state_transition_from_#{state}".to_sym
+ send(transition_method, changed_instance) if self.respond_to?(transition_method,
true)
+ if state_changed?
+ save!
+ true
+ else
+ false
+ end
+ end
+
PRESET_FILTERS_OPTIONS = []
private
@@ -580,4 +591,31 @@ class Deployment < ActiveRecord::Base
def set_new_state
self.state ||= STATE_NEW
end
+
+ def state_transition_from_pending(instance)
+ if instances.all? {|i| i.state == Instance::STATE_RUNNING}
+ self.state = STATE_RUNNING
+ elsif Instance::FAILED_STATES.include?(instance.state)
+ # TODO: initiate rollback. For now if an error occurs, deployment will
+ # stay in pending state
+ end
+ end
+
+ def state_transition_from_running(instance)
+ if instance.state != STATE_RUNNING
+ self.state = STATE_INCOMPLETE
+ end
+ end
+
+ def state_transition_from_incomplete(instance)
+ if instances.all? {|i| i.state == Instance::STATE_RUNNING}
+ self.state = STATE_RUNNING
+ end
+ end
+
+ def state_transition_from_shutting_down(instance)
+ if instance.state == Instance::STATE_STOPPED and instances.all? {|i| i.inactive?}
+ self.state = STATE_STOPPED
+ end
+ end
end
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index ee5b8df..d6eacfc 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -343,6 +343,10 @@ class Instance < ActiveRecord::Base
FAILED_STATES.include?(state)
end
+ def inactive?
+ (FAILED_STATES + [STATE_STOPPED]).include?(state)
+ end
+
def requires_config_server?
not instance_config_xml.nil? or assembly_xml.requires_config_server?
end
diff --git a/src/app/models/instance_observer.rb b/src/app/models/instance_observer.rb
index 244a8a4..77b2e12 100644
--- a/src/app/models/instance_observer.rb
+++ b/src/app/models/instance_observer.rb
@@ -95,6 +95,7 @@ class InstanceObserver < ActiveRecord::Observer
# This can get stale, so reload it -- if it exists
instance.deployment.reload if instance.deployment
if instance.state_changed?
+ instance.deployment.update_state(instance) if instance.deployment
event = Event.new(:source => instance, :event_time => DateTime.now,
:summary => "state changed to #{instance.state}",
:change_hash => instance.changes, :status_code =>
instance.state)
diff --git a/src/spec/models/deployment_spec.rb b/src/spec/models/deployment_spec.rb
index 2878520..69fc583 100644
--- a/src/spec/models/deployment_spec.rb
+++ b/src/spec/models/deployment_spec.rb
@@ -325,20 +325,79 @@ describe Deployment do
end
end
- describe "deployment_state" do
- it "should be pending if only some instances are running" do
- deployment = Factory.build :deployment
- instance = Factory.build(:mock_running_instance, :deployment => deployment)
- instance2 = Factory.build(:mock_pending_instance, :deployment => deployment)
- deployment.stub(:instances) { [instance, instance2] }
- deployment.status.should == :pending
+ describe "deployment state" do
+ context "in running state" do
+ before :each do
+ @deployment.state = Deployment::STATE_RUNNING
+ @deployment.save!
+ @inst1 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_RUNNING)
+ @inst2 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_RUNNING)
+ @deployment.instances << @inst1
+ @deployment.instances << @inst2
+ end
+
+ it "should be incomplete if only some instances are running" do
+ @inst1.state = Instance::STATE_PENDING
+ @inst1.save!
+ @deployment.reload
+ @deployment.state.should == Deployment::STATE_INCOMPLETE
+ end
end
- it "should be stopped if no instances exist" do
- deployment = Factory.build :deployment
- deployment.stub(:instances) {[]}
- deployment.status.should == :stopped
+ context "in pending state" do
+ before :each do
+ @deployment.state = Deployment::STATE_PENDING
+ @deployment.save!
+ @inst1 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_PENDING)
+ @inst2 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_PENDING)
+ @deployment.instances << @inst1
+ @deployment.instances << @inst2
+ end
+
+ it "should be pending if only some instances are running" do
+ @inst1.state = Instance::STATE_RUNNING
+ @inst1.save!
+ @deployment.reload
+ @deployment.state.should == Deployment::STATE_PENDING
+ end
+
+ it "should be running if all instances are running" do
+ @inst1.state = Instance::STATE_RUNNING
+ @inst1.save!
+ @inst2.state = Instance::STATE_RUNNING
+ @inst2.save!
+ @deployment.reload
+ @deployment.state.should == Deployment::STATE_RUNNING
+ end
+ end
+
+ context "in incomplete state" do
+ before :each do
+ @deployment.state = Deployment::STATE_INCOMPLETE
+ @deployment.save!
+ @inst1 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_RUNNING)
+ @inst2 = Factory.create(:instance, :deployment => @deployment, :state =>
Instance::STATE_PENDING)
+ @deployment.instances << @inst1
+ @deployment.instances << @inst2
+ end
+
+ it "should be incomplete if no instances are running" do
+ @inst1.state = Instance::STATE_ERROR
+ @inst1.save!
+ @inst2.state = Instance::STATE_ERROR
+ @inst2.save!
+ @deployment.reload
+ @deployment.state.should == Deployment::STATE_INCOMPLETE
+ end
+
+ it "should be running if all instances are running" do
+ @inst2.state = Instance::STATE_RUNNING
+ @inst2.save!
+ @deployment.reload
+ @deployment.state.should == Deployment::STATE_RUNNING
+ end
end
+
end
describe ".instances.instance_parameters" do
--
1.7.7.6