[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