forked from ManageIQ/manageiq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for copy and compare of ae components
Allows for copy of class, instances and methods across domains.
- Loading branch information
Showing
32 changed files
with
8,783 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
class MiqAeClassCompareFields | ||
attr_reader :compatibilities | ||
attr_reader :incompatibilities | ||
attr_reader :fields_in_use | ||
attr_reader :adds | ||
IGNORE_PROPERTY_NAMES = %w(name owner created_on updated_on updated_by | ||
updated_by_user_id id class_id) | ||
WARNING_PROPERTY_NAMES = %w(priority message display_name default_value substitute | ||
visibility collect scope description condition on_entry | ||
on_exit on_error max_retries max_time) | ||
ERROR_PROPERTY_NAMES = %w(aetype datatype) | ||
|
||
CONGRUENT_SCHEMA = 1 | ||
COMPATIBLE_SCHEMA = 2 | ||
INCOMPATIBLE_SCHEMA = 4 | ||
|
||
def initialize(new_class, old_class) | ||
@new_class = new_class | ||
@old_class = old_class | ||
end | ||
|
||
def compare | ||
load_field_names | ||
initialize_results | ||
venn_list | ||
validate_similar | ||
status | ||
end | ||
|
||
def status | ||
return CONGRUENT_SCHEMA if congruent? | ||
return COMPATIBLE_SCHEMA if compatible? | ||
INCOMPATIBLE_SCHEMA | ||
end | ||
|
||
def congruent? | ||
@adds.empty? && @incompatibilities.empty? && | ||
@compatibilities.empty? && @fields_in_use.empty? && | ||
@deletes.empty? | ||
end | ||
|
||
def compatible? | ||
@incompatibilities.empty? && @deletes.empty? | ||
end | ||
|
||
private | ||
|
||
def initialize_results | ||
@incompatibilities = [] | ||
@compatibilities = [] | ||
@fields_in_use = [] | ||
@adds = [] | ||
@deletes = [] | ||
end | ||
|
||
def load_field_names | ||
@old_names = @old_class.field_names | ||
@new_names = @new_class.field_names | ||
end | ||
|
||
def venn_list | ||
@similar = @new_names & @old_names | ||
@adds = @new_names - @old_names | ||
@deletes = @old_names - @new_names | ||
end | ||
|
||
def validate_similar | ||
@similar.each do |name| | ||
old_field = @old_class.field_hash(name) | ||
new_field = @new_class.field_hash(name) | ||
compare_field_properties(name, old_field, new_field) | ||
end | ||
end | ||
|
||
def compare_field_properties(field_name, old_field, new_field) | ||
old_field.each do |property, value| | ||
next if IGNORE_PROPERTY_NAMES.include?(property) | ||
next if value == new_field[property] | ||
hash = {'property' => property, | ||
'old_value' => value, | ||
'new_value' => new_field[property], | ||
'field_name' => field_name} | ||
@compatibilities << hash if WARNING_PROPERTY_NAMES.include?(property) | ||
@incompatibilities << hash if ERROR_PROPERTY_NAMES.include?(property) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
class MiqAeClassCopy | ||
include MiqAeCopyMixin | ||
DELETE_PROPERTIES = %w(updated_by updated_by_user_id updated_on id | ||
created_on updated_on method_id owner class_id) | ||
|
||
def initialize(class_fqname) | ||
@class_fqname = class_fqname | ||
@src_domain, @partial_ns, @ae_class = MiqAeClassCopy.split(@class_fqname, false) | ||
@src_class = MiqAeClass.find_by_fqname(@class_fqname) | ||
raise "Source class not found #{@class_fqname}" unless @src_class | ||
end | ||
|
||
def to_domain(domain, ns = nil, overwrite = false) | ||
check_duplicity(domain, ns, @src_class.name) | ||
@overwrite = overwrite | ||
@target_ns_fqname = target_ns(domain, ns) | ||
@target_name = @src_class.name | ||
copy | ||
end | ||
|
||
def as(new_name, ns = nil, overwrite = false) | ||
check_duplicity(@src_domain, ns, new_name) | ||
@overwrite = overwrite | ||
@target_ns_fqname = target_ns(@src_domain, ns) | ||
@target_name = new_name | ||
copy | ||
end | ||
|
||
private | ||
|
||
def target_ns(domain, ns) | ||
return "#{domain}/#{@partial_ns}" if ns.nil? | ||
MiqAeNamespace.find_by_fqname(ns, false).nil? ? "#{domain}/#{ns}" : ns | ||
end | ||
|
||
def copy | ||
validate | ||
create_class | ||
copy_schema | ||
@dest_class | ||
end | ||
|
||
def create_class | ||
ns = MiqAeNamespace.find_or_create_by_fqname(@target_ns_fqname, false) | ||
ns.save! | ||
@dest_class = MiqAeClass.create!(:namespace_id => ns.id, | ||
:name => @target_name, | ||
:description => @src_class.description, | ||
:type => @src_class.type, | ||
:display_name => @src_class.display_name, | ||
:inherits => @src_class.inherits, | ||
:visibility => @src_class.visibility) | ||
end | ||
|
||
def copy_schema | ||
@dest_class.ae_fields = add_fields | ||
@dest_class.save! | ||
end | ||
|
||
def add_fields | ||
@src_class.ae_fields.collect do |src_field| | ||
attrs = src_field.attributes.reject { |k, _| DELETE_PROPERTIES.include?(k) } | ||
MiqAeField.new(attrs) | ||
end | ||
end | ||
|
||
def validate | ||
dest_class = MiqAeClass.find_by_fqname("#{@target_ns_fqname}/#{@target_name}") | ||
if dest_class | ||
dest_class.destroy if @overwrite | ||
raise "Destination Class already exists #{dest_class.fqname}" unless @overwrite | ||
end | ||
end | ||
|
||
def check_duplicity(domain, ns, classname) | ||
if domain.downcase == @src_domain.downcase && classname.downcase == @ae_class.downcase | ||
raise "Cannot copy class onto itself" if ns.nil? || ns.downcase == @partial_ns.downcase | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class MiqAeClassYaml | ||
attr_accessor :ae_class_obj | ||
def initialize(filename = nil) | ||
@filename = filename | ||
@ae_class_obj = YAML.load_file(filename) if filename | ||
end | ||
|
||
def field_names | ||
raise "class object has not been set" unless @ae_class_obj | ||
@ae_class_obj['object']['schema'].collect { |x| x['field']['name'].downcase } | ||
end | ||
|
||
def field_hash(name) | ||
raise "class object has not been set" unless @ae_class_obj | ||
field = @ae_class_obj['object']['schema'].detect { |f| f['field']['name'].casecmp(name) == 0 } | ||
raise "field #{name} not found in yaml class #{@filename}" if field.nil? | ||
field['field'] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
class MiqAeInstanceCompareValues | ||
attr_reader :compatibilities | ||
attr_reader :incompatibilities | ||
attr_reader :fields_in_use | ||
attr_reader :adds | ||
IGNORE_PROPERTY_NAMES = %w(name owner created_on updated_on updated_by | ||
updated_by_user_id id class_id instance_id field_id) | ||
WARNING_PROPERTY_NAMES = %w(priority message display_name default_value substitute | ||
visibility collect scope description condition on_entry | ||
on_exit on_error max_retries max_time) | ||
ERROR_PROPERTY_NAMES = %w(aetype datatype) | ||
|
||
CONGRUENT_INSTANCE = 1 | ||
COMPATIBLE_INSTANCE = 2 | ||
INCOMPATIBLE_INSTANCE = 4 | ||
|
||
def initialize(new_instance, old_instance) | ||
@new_instance = new_instance | ||
@old_instance = old_instance | ||
end | ||
|
||
def compare | ||
load_field_names | ||
initialize_results | ||
venn_list | ||
validate_similar | ||
status | ||
end | ||
|
||
def status | ||
return CONGRUENT_INSTANCE if congruent? | ||
return COMPATIBLE_INSTANCE if compatible? | ||
INCOMPATIBLE_INSTANCE | ||
end | ||
|
||
def congruent? | ||
@adds.empty? && @incompatibilities.empty? && | ||
@compatibilities.empty? && @fields_in_use.empty? && | ||
@deletes.empty? | ||
end | ||
|
||
def compatible? | ||
@incompatibilities.empty? && @deletes.empty? | ||
end | ||
|
||
private | ||
|
||
def initialize_results | ||
@incompatibilities = [] | ||
@compatibilities = [] | ||
@fields_in_use = [] | ||
@adds = [] | ||
@deletes = [] | ||
end | ||
|
||
def load_field_names | ||
@old_names = @old_instance.field_names | ||
@new_names = @new_instance.field_names | ||
end | ||
|
||
def venn_list | ||
@similar = @new_names & @old_names | ||
@adds = @new_names - @old_names | ||
@deletes = @old_names - @new_names | ||
end | ||
|
||
def validate_similar | ||
@similar.each do |name| | ||
old_value = @old_instance.field_value_hash(name) | ||
new_value = @new_instance.field_value_hash(name) | ||
compare_value_properties(name, old_value, new_value) | ||
end | ||
end | ||
|
||
def compare_value_properties(field_name, old_value, new_value) | ||
old_value.each do |property, data| | ||
next if IGNORE_PROPERTY_NAMES.include?(property) | ||
next if data == new_value[property] | ||
hash = {'property' => property, | ||
'old_data' => data, | ||
'new_data' => new_value[property], | ||
'field_name' => field_name} | ||
@compatibilities << hash if WARNING_PROPERTY_NAMES.include?(property) | ||
@incompatibilities << hash if ERROR_PROPERTY_NAMES.include?(property) | ||
end | ||
end | ||
end |
Oops, something went wrong.