[PATCH conductor 3/4] Change deployment state when instance state changes
Jozef Zigmund
jzigmund at redhat.com
Thu May 3 14:13:25 UTC 2012
On Wednesday 25 April 2012 14:55:01 jprovazn at redhat.com wrote:
> From: Jan Provaznik <jprovazn at 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
^^ in fact there should be other state than Instance::STATE_PENDING(transition
from RUNNING to PENDING is not allowed)
> + @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
More information about the aeolus-devel
mailing list