You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2012/04/17 15:39:49 UTC

[PATCH core 10/32] Core: Added hardware_profile model and moved instance_states to models

From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/models/hardware_profile.rb |  194 ++++++++++++++++++++++
 server/lib/deltacloud/models/state_machine.rb    |   99 +++++++++++
 server/lib/deltacloud/state_machine.rb           |  115 -------------
 3 files changed, 293 insertions(+), 115 deletions(-)
 create mode 100644 server/lib/deltacloud/models/hardware_profile.rb
 create mode 100644 server/lib/deltacloud/models/state_machine.rb
 delete mode 100644 server/lib/deltacloud/state_machine.rb

diff --git a/server/lib/deltacloud/models/hardware_profile.rb b/server/lib/deltacloud/models/hardware_profile.rb
new file mode 100644
index 0000000..45e77a1
--- /dev/null
+++ b/server/lib/deltacloud/models/hardware_profile.rb
@@ -0,0 +1,194 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  class HardwareProfile
+
+    UNITS = {
+      :memory => "MB",
+      :storage => "GB",
+      :architecture => "label",
+      :cpu => "count"
+    }
+
+    def self.unit(name)
+      UNITS[name]
+    end
+
+    class Property
+      attr_reader :name, :kind, :default
+      # kind == :range
+      attr_reader :first, :last
+      # kind == :enum
+      attr_reader :values
+      # kind == :fixed
+      attr_reader :value
+
+      def initialize(name, values, opts = {})
+        @name = name
+        if values.is_a?(Range)
+          @kind = :range
+          @first = values.first
+          @last = values.last
+          @default = values.first
+        elsif values.is_a?(Array)
+          @kind = :enum
+          @values = values
+          @default = values.first
+        else
+          @kind = :fixed
+          @value = values
+          @default = @value
+        end
+        @default = opts[:default] if opts[:default]
+      end
+
+      def unit
+        HardwareProfile.unit(name)
+      end
+
+      def param
+        :"hwp_#{name}"
+      end
+
+      def fixed?
+        kind == :fixed
+      end
+
+      def valid?(v)
+        v = convert_property_value_type(v)
+        case kind
+          # NOTE:
+          # Currently we cannot validate fixed values because of UI
+          # limitation. In UI we have multiple hwp_* properties which overide
+          # each other.
+          # Then provider have one 'static' hardware profile and one
+          # 'customizable' when user select the static one the UI also send
+          # values from the customizable one (which will lead to a validation
+          # error because validation algorith will think that client want to
+          # overide fixed values.
+          #
+          # when :fixed then (v == @default.to_s)
+          when :fixed then true
+          when :range then match_type?(first, v) and (first..last).include?(v)
+          when :enum then match_type?(values.first, v) and values.include?(v)
+          else false
+        end
+      end
+
+      def to_param
+        if defined? Sinatra::Rabbit
+          Sinatra::Rabbit::Param.new([param, :string, :optional, []])
+        end
+      end
+
+      def include?(v)
+        if kind == :fixed
+          return v == value
+        else
+          return values.include?(v)
+        end
+      end
+
+      private
+
+      def match_type?(reference, value)
+        true if reference.class == value.class
+      end
+
+      def convert_property_value_type(v)
+        return v.to_f if v =~ /(\d+)\.(\d+)/
+        return v.to_i if v =~ /(\d+)/
+        v.to_s
+      end
+    end
+
+    class << self
+      def property(prop)
+        define_method(prop) do |*args|
+          values, opts, *ignored = *args
+          instvar = :"@#{prop}"
+          unless values.nil?
+            @properties[prop] = Property.new(prop, values, opts || {})
+          end
+          @properties[prop]
+        end
+      end
+    end
+
+    attr_reader :name
+    property :cpu
+    property :architecture
+    property :memory
+    property :storage
+
+    def initialize(name,&block)
+      @properties   = {}
+      @name         = name
+      instance_eval &block if block_given?
+    end
+
+    def each_property(&block)
+      @properties.each_value { |prop| yield prop }
+    end
+
+    def properties
+      @properties.values
+    end
+
+    def property(name)
+      @properties[name.to_sym]
+    end
+
+    def default?(prop, v)
+      p = @properties[prop.to_sym]
+      p && p.default.to_s == v
+    end
+
+    def to_hash
+      props = []
+      self.each_property do |p|
+        if p.kind.eql? :fixed
+          props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
+        else
+          param = { :operation => "create", :method => "post", :name => p.name }
+          if p.kind.eql? :range
+            param[:range] = { :first => p.first, :last => p.last }
+          elsif p.kind.eql? :enum
+            param[:enum] = p.values.collect { |v| { :entry => v } }
+          end
+          param
+          props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
+        end
+      end
+      {
+        :id => self.name,
+        :properties => props
+      }
+    end
+
+    def include?(prop, v)
+      p = @properties[prop]
+      p.nil? || p.include?(v)
+    end
+
+    def params
+      @properties.values.inject([]) { |m, prop|
+        m << prop.to_param
+      }.compact
+    end
+  end
+end
diff --git a/server/lib/deltacloud/models/state_machine.rb b/server/lib/deltacloud/models/state_machine.rb
new file mode 100644
index 0000000..19fb9f2
--- /dev/null
+++ b/server/lib/deltacloud/models/state_machine.rb
@@ -0,0 +1,99 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  class StateMachine
+
+    attr_reader :states
+    def initialize(&block)
+      @states  = []
+      instance_eval &block if block
+    end
+
+    def start()
+      state(:start)
+    end
+
+    def finish()
+      state(:finish)
+    end
+
+    def state(name)
+      state = @states.find{|e| e.name == name.to_sym}
+      if ( state.nil? )
+        state = State.new( self, name.to_sym )
+        @states << state
+      end
+      state
+    end
+
+    def method_missing(sym,*args)
+      return state( sym ) if ( args.empty? )
+      super( sym, *args )
+    end
+
+    class State
+
+      attr_reader :name
+      attr_reader :transitions
+
+      def initialize(machine, name)
+        @machine = machine
+        @name    = name
+        @transitions = []
+      end
+
+      def to_s
+        self.name.to_s
+      end
+
+      def to(destination_name)
+        destination = @machine.state(destination_name)
+        transition = Transition.new( @machine, destination )
+        @transitions << transition
+        transition
+      end
+
+    end
+
+    class Transition
+
+      attr_reader :destination
+      attr_reader :action
+
+      def initialize(machine, destination)
+        @machine = machine
+        @destination = destination
+        @auto   = false
+        @action = nil
+      end
+
+      def automatically
+        @auto = true
+      end
+
+      def automatically?
+        @auto
+      end
+
+      def on(action)
+        @action = action
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/state_machine.rb b/server/lib/deltacloud/state_machine.rb
deleted file mode 100644
index facd4ba..0000000
--- a/server/lib/deltacloud/state_machine.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud
-  class StateMachine
-
-    attr_reader :states
-    def initialize(opts = {}, &block)
-      @all_states = opts[:all_states]
-      @all_actions = opts[:all_actions]
-      @states  = []
-      instance_eval &block if block
-    end
-
-    def start()
-      state(:start)
-    end
-
-    def finish()
-      state(:finish)
-    end
-
-    def state(name)
-      unless valid_state_name?(name)
-        raise "State '#{name}' not in list of allowed states"
-      end
-      state = @states.find{|e| e.name == name.to_sym}
-      if ( state.nil? )
-        state = State.new( self, name.to_sym )
-        @states << state
-      end
-      state
-    end
-
-    def valid_state_name?(name)
-      @all_states.nil? || @all_states.include?(name.to_sym)
-    end
-
-    def valid_action_name?(name)
-      @all_actions.nil? || @all_actions.include?(name.to_sym)
-    end
-
-    def method_missing(sym,*args)
-      return state( sym ) if ( args.empty? )
-      super( sym, *args )
-    end
-
-    class State
-
-      attr_reader :name
-      attr_reader :transitions
-
-      def initialize(machine, name)
-        @machine = machine
-        @name    = name
-        @transitions = []
-      end
-
-      def to_s
-        self.name.to_s
-      end
-
-      def to(destination_name)
-        destination = @machine.state(destination_name)
-        transition = Transition.new( @machine, destination )
-        @transitions << transition
-        transition
-      end
-
-    end
-
-    class Transition
-
-      attr_reader :destination
-      attr_reader :action
-
-      def initialize(machine, destination)
-        @machine = machine
-        @destination = destination
-        @auto   = false
-        @action = nil
-      end
-
-      def automatically
-        @auto = true
-      end
-
-      def automatically?
-        @auto
-      end
-
-      def on(action)
-        unless @machine.valid_action_name?(action)
-          raise "Action '#{action}' not in list of allowed actions"
-        end
-        @action = action
-      end
-
-    end
-
-  end
-end
-- 
1.7.10