From 4d4a32d651a1eed14fb1d0b58ff021d82b3cd74e Mon Sep 17 00:00:00 2001 From: Nestor Date: Tue, 3 Dec 2013 16:59:44 -0600 Subject: [PATCH 1/4] Added ref specs, basic ref execution --- lib/harp-runtime/interpreter.rb | 8 ++++++++ spec/lang_addon_spec.rb | 26 ++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/harp-runtime/interpreter.rb b/lib/harp-runtime/interpreter.rb index d2a55b0..023f0cd 100644 --- a/lib/harp-runtime/interpreter.rb +++ b/lib/harp-runtime/interpreter.rb @@ -94,6 +94,14 @@ def create(resource_name) if ! advance() then return self end @@logger.debug "Launching resource: #{resource_name}." resource = @resourcer.get resource_name + #Iterate over values to check for refs + resource.each do |key, value| + if value.is_a?(Hash) + create(value["ref"]) + resource[key] = "testLC" + end + end + created = @mutator.create(resource_name, resource) created.harp_script = @harp_script result = {:create => resource_name} diff --git a/spec/lang_addon_spec.rb b/spec/lang_addon_spec.rb index ea171b8..da30b56 100644 --- a/spec/lang_addon_spec.rb +++ b/spec/lang_addon_spec.rb @@ -13,6 +13,20 @@ "type": "Std::ComputeInstance", "imageId": "ami-d0f89fb9", "instanceType": "t1.micro" + }, + "lc1": { + "type": "Std::LaunchConfiguration", + "image_id": "ami-d0f89fb9", + "instance_type": "t1.micro", + "id": "testLC" + }, + "asg1": { + "type": "Std::AutoScalingGroup", + "id": "testASG", + "launch_configuration_name": {"ref": "lc1"}, + "availability_zones": "us-east-1", + "max_size": "1", + "min_size": "1" } } } @@ -28,6 +42,10 @@ def copy() engine.copy("computeInstance1", "path1", "path2") end +def create() + engine.create("asg1") +end + OUTER describe Harp::HarpInterpreter, "#play" do @@ -38,13 +56,9 @@ def copy() end let(:interpreter) { Harp::HarpInterpreter.new(interpreter_context()) } - it "handles commands" do - results = interpreter.play("command", interpreter_context) + it "handles refs" do + results = interpreter.play("create", interpreter_context) expect(results).not_to be_empty end - it "handles copies" do - results = interpreter.play("copy", interpreter_context) - expect(results).not_to be_empty - end end From 5f152fba13d39d3438e91e259b7599707f138028 Mon Sep 17 00:00:00 2001 From: Nestor Date: Wed, 4 Dec 2013 11:49:39 -0600 Subject: [PATCH 2/4] Added ref support --- lib/harp-runtime/interpreter.rb | 12 +++-------- lib/harp-runtime/resourcer.rb | 38 ++++++++++++++++++++++++++++++--- spec/lang_addon_spec.rb | 14 ++++++++++-- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/lib/harp-runtime/interpreter.rb b/lib/harp-runtime/interpreter.rb index 023f0cd..353b3f4 100644 --- a/lib/harp-runtime/interpreter.rb +++ b/lib/harp-runtime/interpreter.rb @@ -94,15 +94,9 @@ def create(resource_name) if ! advance() then return self end @@logger.debug "Launching resource: #{resource_name}." resource = @resourcer.get resource_name - #Iterate over values to check for refs - resource.each do |key, value| - if value.is_a?(Hash) - create(value["ref"]) - resource[key] = "testLC" - end - end - - created = @mutator.create(resource_name, resource) + deps = @resourcer.get_dep(resource_name) + deps.each {|ref| create(ref)} + created = @mutator.create(resource_name, resource) created.harp_script = @harp_script result = {:create => resource_name} args = {:action => :create} diff --git a/lib/harp-runtime/resourcer.rb b/lib/harp-runtime/resourcer.rb index be8dab3..88598ee 100644 --- a/lib/harp-runtime/resourcer.rb +++ b/lib/harp-runtime/resourcer.rb @@ -5,13 +5,16 @@ module Harp require "json" - + require "rgl/adjacency" + # Resourcer keeps track of defined resources and provides lookup over them. class Resourcer @@logger = Logging.logger[self] def initialize(harp_id) + @dep_graph = RGL::DirectedAdjacencyGraph[] + @dependencies = Hash.new [] @harp_id = harp_id @resources = nil @config = nil @@ -37,14 +40,43 @@ def get_existing(resource_name) @resources[resource_name] end + # Retrieve a resource dependency list from the set + def get_dep(resource_name) + @@logger.debug "Looking for : #{resource_name}'s dependencies" + @dependencies[resource_name] + end + private def digest(content) json = JSON.parse(content) @config = json.has_key?("Config") ? json["Config"] : nil @resources = json.has_key?("Resources") ? json["Resources"] : nil - # TODO: parse into graph and determine dependencies. + # TODO: parse into graph and determince dependencies. + determine_deps end - end + + def determine_deps + @resources.each do |name, content| + match_deps(name, content, "ref") + end + end + + #Iterate over values to check for specified item + def match_deps(name, content, item) + content.each do |key, value| + if value.is_a?(Hash) + dep = value[item] + unless dep.nil? + content[key] = @resources.has_key?(dep) ? @resources[dep]["id"] : nil + @dependencies[name] += [dep] + @dep_graph.add_edge(dep, name) + end + end + end + + end + + end end \ No newline at end of file diff --git a/spec/lang_addon_spec.rb b/spec/lang_addon_spec.rb index da30b56..b358513 100644 --- a/spec/lang_addon_spec.rb +++ b/spec/lang_addon_spec.rb @@ -28,6 +28,7 @@ "max_size": "1", "min_size": "1" } + } } END @@ -56,9 +57,18 @@ def create() end let(:interpreter) { Harp::HarpInterpreter.new(interpreter_context()) } + it "handles commands" do + results = interpreter.play("command", interpreter_context) + expect(results).not_to be_empty + end + + it "handles copies" do + results = interpreter.play("copy", interpreter_context) + expect(results).not_to be_empty + end + it "handles refs" do results = interpreter.play("create", interpreter_context) expect(results).not_to be_empty end - -end +end \ No newline at end of file From 2e77740f2ed06eac601f814c7a6a2038f9951c01 Mon Sep 17 00:00:00 2001 From: Nestor Date: Wed, 4 Dec 2013 13:16:43 -0600 Subject: [PATCH 3/4] changed conflicting names in spec --- spec/lang_addon_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lang_addon_spec.rb b/spec/lang_addon_spec.rb index b358513..a41bd0d 100644 --- a/spec/lang_addon_spec.rb +++ b/spec/lang_addon_spec.rb @@ -18,11 +18,11 @@ "type": "Std::LaunchConfiguration", "image_id": "ami-d0f89fb9", "instance_type": "t1.micro", - "id": "testLC" + "id": "langSpecLc" }, "asg1": { "type": "Std::AutoScalingGroup", - "id": "testASG", + "id": "langSpecASG", "launch_configuration_name": {"ref": "lc1"}, "availability_zones": "us-east-1", "max_size": "1", From b6ebb099475bc9ae08f8fea72f88baac22767f6c Mon Sep 17 00:00:00 2001 From: Nestor Date: Wed, 4 Dec 2013 15:00:13 -0600 Subject: [PATCH 4/4] Added reference tests in new file, check for circular dependencies --- lib/harp-runtime/resourcer.rb | 9 ++++--- spec/lang_addon_spec.rb | 24 ----------------- spec/reference_spec.rb | 50 +++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 spec/reference_spec.rb diff --git a/lib/harp-runtime/resourcer.rb b/lib/harp-runtime/resourcer.rb index 88598ee..d06738f 100644 --- a/lib/harp-runtime/resourcer.rb +++ b/lib/harp-runtime/resourcer.rb @@ -6,6 +6,7 @@ module Harp require "json" require "rgl/adjacency" + require "rgl/topsort" # Resourcer keeps track of defined resources and provides lookup over them. class Resourcer @@ -52,15 +53,17 @@ def digest(content) json = JSON.parse(content) @config = json.has_key?("Config") ? json["Config"] : nil @resources = json.has_key?("Resources") ? json["Resources"] : nil - # TODO: parse into graph and determince dependencies. - determine_deps + parse_into_graph end - def determine_deps + def parse_into_graph @resources.each do |name, content| match_deps(name, content, "ref") end + unless @dep_graph.acyclic? + raise "Found circular dependency" + end end #Iterate over values to check for specified item diff --git a/spec/lang_addon_spec.rb b/spec/lang_addon_spec.rb index a41bd0d..8b3f48b 100644 --- a/spec/lang_addon_spec.rb +++ b/spec/lang_addon_spec.rb @@ -13,22 +13,7 @@ "type": "Std::ComputeInstance", "imageId": "ami-d0f89fb9", "instanceType": "t1.micro" - }, - "lc1": { - "type": "Std::LaunchConfiguration", - "image_id": "ami-d0f89fb9", - "instance_type": "t1.micro", - "id": "langSpecLc" - }, - "asg1": { - "type": "Std::AutoScalingGroup", - "id": "langSpecASG", - "launch_configuration_name": {"ref": "lc1"}, - "availability_zones": "us-east-1", - "max_size": "1", - "min_size": "1" } - } } END @@ -43,10 +28,6 @@ def copy() engine.copy("computeInstance1", "path1", "path2") end -def create() - engine.create("asg1") -end - OUTER describe Harp::HarpInterpreter, "#play" do @@ -66,9 +47,4 @@ def create() results = interpreter.play("copy", interpreter_context) expect(results).not_to be_empty end - - it "handles refs" do - results = interpreter.play("create", interpreter_context) - expect(results).not_to be_empty - end end \ No newline at end of file diff --git a/spec/reference_spec.rb b/spec/reference_spec.rb new file mode 100644 index 0000000..2843fae --- /dev/null +++ b/spec/reference_spec.rb @@ -0,0 +1,50 @@ +require File.dirname(__FILE__) + '/spec_helper' +require "rubygems" +require "harp_runtime" +require "evalhook" + +ADDON_SCRIPT = <