claudius 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Claudius
2
2
 
3
- Claudius is a easy-to-use domain specific language for clouds experiments. Language is build on [fog.io](http://fog.io), which enables flexible and powerfull way to manage virtual machine instances on various cloude poviders. Connections with virtual machines is based on ssh. To provide information experiment flow, DSL generates readable graph of execution.
3
+ Claudius is an easy-to-use domain specific language for cloud experiments. It has been designed to speed up process of building distributed experiments and highly reduce time of remote machines configuration. To avoid vendor lock-in, Claudius was build on top of fog.io library, which enables flexible and powerful way to manage machine instances at various cloud providers. Remote commands execution is based on SSH protocol (SSH-2). DLS allow users to generate readable execution graph, which is extremely useful for experiment flow verification and help avoid wasting money.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,14 +13,14 @@ If you want export execution tree to image you need [Graphivz](http://www.graphv
13
13
 
14
14
  ## Keywords
15
15
 
16
- * **experiment** - central part of claudius. Method defines a new experiment. Parameters:
17
- * **experiment_name**
18
- * **body** - block of code describing performed experiment
16
+ * **experiment** -- main part of Claudius DLS, which defines a new experiment. After command, you are obligated to provide 2 parameters:
17
+ * **experiment_name** - string, which is the name of the experiment
18
+ * **body** - block of code describing designed experiment
19
19
 
20
- You may call the following methods on returned experiment object:
20
+ You are allowed to call following methods on returned experiment object:
21
21
 
22
- * **run** - method starts previously defined experiment,
23
- * **export_tree(path = 'execution_tree_path')** - method creates an execution graph of experiment and save it as an image
22
+ * **run** - method starts previously designed experiment.
23
+ * **export_tree(path = 'execution_tree_path')** - method generates readable execution graph. Graph is saved as an image and in .dot file format (graph description language) - for further user processing.
24
24
 
25
25
  * **define_providers** - method takes as a parameter description of machines used in experiment. In experiments You are allowed to use 2 different types of machines
26
26
 
@@ -54,8 +54,8 @@ In order to authenticate in AWS services (at other cloud providers also) you are
54
54
  "aws_access_key_id" : "XXXXXXXXXXXXXXXXXXXX",
55
55
  "aws_secret_access_key" : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
56
56
  "key_name" : "My-irleand-key",
57
- "groups" : "My-irleand-group"
58
- "path_to_pem_file" : "./pems/my-irleand-key.pem"
57
+ "groups" : ["My-irleand-group"]
58
+ "private_key_path" : "./pems/my-irleand-key.pem"
59
59
  }
60
60
  ```
61
61
 
data/claudius.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "claudius"
7
- spec.version = "0.0.4"
7
+ spec.version = "0.0.5"
8
8
  spec.authors = ["radk0s", "blost"]
9
9
  spec.email = ["rachamot@gmail.com", "piotr.skibiak@gmail.com"]
10
10
  spec.description = 'Claudius is an easy-to-use domain specific language for cloud experiments. ' +
data/examples/ping.rb CHANGED
@@ -1,11 +1,12 @@
1
-
2
1
  # Ping
3
2
  # ---------
4
3
  # This example shows how to conduct simple experiment with ping command.
5
4
  #
6
5
 
7
6
  require 'claudius'
7
+
8
8
  config = load_config('./user_config.json')
9
+
9
10
  execution_tree = experiment 'Hello' do
10
11
  define_providers do
11
12
  cloud('aws', :provider => config['provider'],
@@ -13,29 +14,27 @@ execution_tree = experiment 'Hello' do
13
14
  :endpoint => 'https://ec2.eu-west-1.amazonaws.com/',
14
15
  :aws_access_key_id => config['aws_access_key_id'],
15
16
  :aws_secret_access_key => config['aws_secret_access_key'])
16
- .create_instances(['t2.micro=>in1'],
17
+ .create_instances(['t1.micro=>instance1', 't1.micro=>instance2', 't1.micro=>instance3'],
17
18
  :username => 'ubuntu',
18
- :private_key_path =>config['path_to_pem_file'],
19
+ :private_key_path =>config['private_key_path'],
19
20
  :key_name => config['key_name'],
20
- :image_id => config['image_id'],
21
21
  :groups => config['groups'])
22
22
  end
23
- foreach ['in1'] do |instance_name|
24
- concurrent do
25
- on 'localhost' do
26
- execute do
27
- ssh "ping #{getInstance(instance_name).host} -c 3"
28
- end
23
+ foreach ['instance1', 'instance2', 'instance3'], concurrently do |instance_name|
24
+ on 'localhost' do
25
+ execute do
26
+ ssh "ping #{getInstance(instance_name).host} -c 3"
29
27
  end
30
- on instance_name do
31
- execute do
32
- ssh "ping #{getInstance(instance_name).host} -c 3"
33
- ssh "echo Hello World! > TestFile"
34
- end
28
+ end
29
+ on instance_name do
30
+ execute do
31
+ ssh "ping #{getInstance(instance_name).host} -c 3"
32
+ ssh "echo Hello World! > TestFile"
35
33
  end
36
34
  end
37
35
  end
38
36
  end
39
37
 
40
38
  ap execution_tree.run
41
- execution_tree.export_tree('tree')
39
+ execution_tree.export_tree('tree')
40
+ execution_tree.destroy_machines
@@ -22,4 +22,4 @@ end
22
22
  # execute tree and print result time using *awesome_print*
23
23
  ap execution_tree.run
24
24
  # export tree to tree.png and tree.dot
25
- execution_tree.export_tree('tree')
25
+ execution_tree.export_tree('tree')
@@ -0,0 +1,41 @@
1
+ require 'claudius'
2
+ config = load_config('./user_config.json')
3
+
4
+ execution_tree = experiment 'Hello' do
5
+ define_providers do
6
+ cloud('aws', :provider => config['provider'],
7
+ :region =>config['region'],
8
+ :aws_access_key_id => config['aws_access_key_id'],
9
+ :aws_secret_access_key => config['aws_secret_access_key'])
10
+ .create_instances(['t1.micro=>instance1','t1.micro=>instance2','t1.micro=>instance3'],
11
+ :username => 'ubuntu',
12
+ :private_key_path =>config['private_key_path'],
13
+ :key_name => config['key_name'],
14
+ :groups => config['groups'])
15
+ end
16
+ foreach ['instance1','instance2','instance3'], concurrently do |instance|
17
+ on instance do
18
+ before do
19
+ ssh "mkdir test"
20
+ end
21
+ concurrent do
22
+ foreach 1..3 do |m|
23
+ execute do
24
+ ssh "cd test"
25
+ ssh "touch testFile#{m}"
26
+ end
27
+ end
28
+ execute do
29
+ ssh "ls"
30
+ end
31
+ end
32
+ after do
33
+ ssh "rm -rf test"
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ ap execution_tree.run
40
+ execution_tree.export_tree('tree')
41
+ execution_tree.destroy_machines
@@ -11,17 +11,26 @@ class CloudProvider
11
11
  @instances = Array.new
12
12
  end
13
13
 
14
+ def create_instance(instance_type, parameters)
15
+ puts 'creating machine: ' + instance_type
16
+ parameters.store(:flavor_id, instance_type.split('=>').first)
17
+ name = ("#{@provider_name}:" + instance_type).split('=>')
18
+ machine = @provider.servers.bootstrap(parameters)
19
+ @instances.push(machine)
20
+ machine_id = @provider.servers.get(machine.id)
21
+ vm = VirtualMachine.new(machine_id.public_ip_address, parameters[:username], :keys => parameters[:private_key_path])
22
+ @virtual_machines.store(name.last, vm)
23
+ end
24
+
14
25
  def create_instances(instances_types, *parameters)
15
- parameters = parameters[0]
26
+ threads = []
16
27
  instances_types.each do |instance_type|
17
- puts 'creating machine: ' + instance_type
18
- parameters.store(:flavor_id, instance_type.split('=>').first)
19
- name = ("#{@provider_name}:" + instance_type).split('=>')
20
- machine = @provider.servers.bootstrap(parameters)
21
- @instances.push(machine)
22
- machine_id = @provider.servers.get(machine.id)
23
- vm = VirtualMachine.new(machine_id.public_ip_address, parameters[:username], :keys => parameters[:private_key_path])
24
- @virtual_machines.store(name.last, vm)
28
+ threads.push(Thread.fork do
29
+ create_instance(instance_type, parameters[0])
30
+ end)
31
+ end
32
+ threads.each do |thread|
33
+ thread.join
25
34
  end
26
35
  end
27
36
 
@@ -22,8 +22,8 @@ class MachineManager
22
22
  end
23
23
  end
24
24
 
25
- def manual(name, host, username, *args)
26
- vm = VirtualMachine.new(host, username, *args)
25
+ def manual(name, ip, username, *args)
26
+ vm = VirtualMachine.new(ip, username, *args)
27
27
  @virtual_machines.store(name, vm)
28
28
  end
29
29
 
@@ -8,10 +8,10 @@ def s_ssh(session, commands)
8
8
  end
9
9
 
10
10
  class VirtualMachine
11
- attr_accessor :host, :username, :args, :log_file, :active
11
+ attr_accessor :ip_address, :username, :args, :log_file, :active
12
12
 
13
- def initialize(host, username, *args)
14
- @host = host
13
+ def initialize(ip_address, username, *args)
14
+ @ip_address = ip_address
15
15
  @username = username
16
16
  args[0].store(:timeout, 5)
17
17
  @args = args
@@ -19,19 +19,19 @@ class VirtualMachine
19
19
  end
20
20
 
21
21
  def to_s
22
- "[host: #{host}, user: #{username}]"
22
+ "[IP: #{ip_address}, user: #{username}]"
23
23
  end
24
24
 
25
25
  def ssh_test(session,command)
26
26
  res = session.exec!(command)
27
27
  puts res
28
- if (res!='' and res!="attributes.json\n")
28
+ if res!='' and res!="attributes.json\n"
29
29
  @active = true
30
30
  end
31
31
  end
32
32
 
33
33
  def invoke(commands)
34
- Net::SSH.start(host, username, *args) do |ssh|
34
+ Net::SSH.start(ip_address, username, *args) do |ssh|
35
35
  commands.each do |command|
36
36
  print command , "\n"
37
37
  s_ssh ssh, command
@@ -1,105 +1,124 @@
1
1
  require 'concurrent_node.rb'
2
2
  require 'on_node.rb'
3
+ require 'foreach_node.rb'
3
4
  require 'execution_node.rb'
4
5
 
5
6
  def experiment(name, &block)
6
- experiment = Experiment.new(name, &block)
7
+ Experiment.new(name, &block)
7
8
  end
8
9
 
9
10
  class Experiment
10
- def initialize(name, &block)
11
- @child_node
12
- @current_node = nil
13
- @tmp_asynchronously = false
14
- @tmp_safely = false
15
- @tmp_execution_place = 'localhost'
16
- @in_after_scope = false
17
- @in_before_scope = false
18
- @root = Node.new(nil,block)
19
- @current_node = @root
20
- @root.name = name
21
- instance_eval(&block) if block
22
- end
23
-
24
- def asynchronously
25
- @child_node = ConcurrentNode.new(@current_node, nil)
26
- @current_node.node_list.push(@child_node)
27
- @current_node = @child_node
28
- end
29
-
30
- def safely
31
- puts 'should be safely'
32
- end
33
-
34
- def before(*args, &block)
35
- @in_before_scope = true
36
- yield
37
- @in_before_scope = false
38
- end
39
-
40
- def after(*args, &block)
41
- @in_after_scope = true
42
- yield
43
- @in_after_scope = false
44
- end
45
-
46
- def foreach(parameters, *args, &block)
47
- puts @current_node.name
48
- parameters.each do |parameter|
49
- @child_node = Node.new(@current_node, block)
50
- @child_node.is_safely = @tmp_safely
51
- @child_node.is_asynchronously = @tmp_asynchronously
52
- @current_node.node_list.push(@child_node)
53
- @current_node = @child_node
54
- block.call parameter
55
- @current_node = @current_node.parent
11
+ def initialize(name, &block)
12
+ @child_node
13
+ @current_node = nil
14
+ @tmp_concurrently = false
15
+ @tmp_safely = false
16
+ @tmp_execution_place = 'localhost'
17
+ @in_after_scope = false
18
+ @in_before_scope = false
19
+ @root = Node.new(nil, block)
20
+ @current_node = @root
21
+ @root.name = name
22
+ instance_eval(&block) if block
56
23
  end
57
- end
58
-
59
- def on(instance, *args, &block)
60
- @child_node = OnNode.new(@current_node, instance, block)
61
-
62
- @current_node.node_list.push(@child_node)
63
- @current_node = @child_node
64
- block.call
65
- @current_node = @current_node.parent
66
- end
67
-
68
- def concurrent(*args, &block)
69
- @child_node = ConcurrentNode.new(@current_node, block)
70
- @current_node.node_list.push(@child_node)
71
- @current_node = @child_node
72
- block.call
73
- @current_node = @current_node.parent
74
- end
75
-
76
- def execute(*args, &block)
77
- @child_node = ExecutionNode.new(@current_node, block)
78
- @child_node.is_safely = @tmp_safely
79
- @child_node.is_asynchronously = @tmp_asynchronously
80
- @current_node.node_list.push(@child_node)
81
- @current_node = @child_node
82
- block.call
83
- @current_node = @current_node.parent
84
- end
85
-
86
- def ssh(command)
87
- if @in_before_scope
88
- @current_node.before_list.push(command)
89
- elsif $in_after_scope
90
- @current_node.after_list.push(command)
91
- else
92
- @current_node.commands.push(command)
24
+
25
+ def concurrently
26
+ @tmp_concurrently = true
27
+ end
28
+
29
+ def safely
30
+ @tmp_safely = true
31
+ end
32
+
33
+ def concurrent(*args, &block)
34
+ @child_node = ConcurrentNode.new(@current_node, block)
35
+ @current_node.node_list.push(@child_node)
36
+ @current_node = @child_node
37
+ block.call
38
+ @current_node = @current_node.parent
39
+ end
40
+
41
+ def before(*args, &block)
42
+ @in_before_scope = true
43
+ yield
44
+ @in_before_scope = false
45
+ end
46
+
47
+ def after(*args, &block)
48
+ @in_after_scope = true
49
+ yield
50
+ @in_after_scope = false
51
+ end
52
+
53
+ def foreach(parameters, *args, &block)
54
+
55
+ @current_node = ForeachNode.new(@current_node, block)
56
+
57
+ @current_node.is_safely = @tmp_safely
58
+ @tmp_safely = false
59
+
60
+ @current_node.is_concurrently = @tmp_concurrently
61
+ @tmp_concurrently = false
62
+
63
+ @current_node.parent.node_list.push(@current_node)
64
+
65
+ parameters.each do |parameter|
66
+ @child_node = Node.new(@current_node, block)
67
+ @child_node.name = "Parameter: #{parameter}"
68
+ @current_node.node_list.push(@child_node)
69
+ @current_node = @child_node
70
+ block.call parameter
71
+ @current_node = @current_node.parent
72
+ end
73
+
74
+ @current_node = @current_node.parent
75
+ end
76
+
77
+ def on(instance, *args, &block)
78
+ @child_node = OnNode.new(@current_node, instance, block)
79
+
80
+ @current_node.node_list.push(@child_node)
81
+ @current_node = @child_node
82
+ block.call
83
+ @current_node = @current_node.parent
84
+ end
85
+
86
+ def execute(*args, &block)
87
+ @child_node = ExecutionNode.new(@current_node, block)
88
+ @child_node.is_safely = @tmp_safely
89
+ @child_node.is_concurrently = @tmp_concurrently
90
+ @current_node.node_list.push(@child_node)
91
+ @current_node = @child_node
92
+ block.call
93
+ @current_node = @current_node.parent
94
+ end
95
+
96
+ def ssh(command)
97
+ if @in_before_scope
98
+ @current_node.before_list.push(command)
99
+ elsif @in_after_scope
100
+ @current_node.after_list.push(command)
101
+ else
102
+ @current_node.commands.push(command)
103
+ end
93
104
  end
94
- end
95
105
 
96
- def run
97
- @root.run(nil)
98
- # $vms_manager.destroy_machines
99
- end
106
+ def run
107
+ begin
108
+ @root.run(nil)
109
+ rescue
110
+ '{error : true}'
111
+ end
112
+ end
100
113
 
101
- def export_tree(path = 'execution_tree')
102
- @root.print_tree(path)
103
- end
114
+ def destroy_machines
115
+ if $vms_manager
116
+ $vms_manager.destroy_machines
117
+ end
118
+ end
119
+
120
+ def export_tree(path = 'execution_tree')
121
+ @root.print_tree(path)
122
+ end
104
123
 
105
124
  end
@@ -23,7 +23,7 @@ class ConcurrentNode < Node
23
23
  pids.each{|pid| Process.waitpid(pid)}
24
24
 
25
25
  after_exec(instance, @total_time)
26
- return @total_time
26
+ @total_time
27
27
  end
28
28
 
29
29
  def draw_block(graph)
@@ -42,7 +42,7 @@ class ExecutionNode < Node
42
42
  finish = Time.now
43
43
 
44
44
  @total_time[:total] = finish - start
45
- return @total_time
45
+ @total_time
46
46
  end
47
47
 
48
48
  end
@@ -0,0 +1,40 @@
1
+ require 'node.rb'
2
+
3
+ class ForeachNode < Node
4
+ def initialize (parent, block)
5
+ super(parent, block)
6
+ self.name = "[Foreach]\n"
7
+ end
8
+
9
+ def run(instance)
10
+ init_time
11
+ before_exec(instance, @total_time)
12
+ begin
13
+ if is_concurrently
14
+ pids = []
15
+ node_list.each do |node|
16
+ pids << fork do
17
+ @total_time[:exec].push(node.run(instance))
18
+ end
19
+ end
20
+ pids.each{|pid| Process.waitpid(pid)}
21
+ else
22
+ node_list.each do |node|
23
+ @total_time[:exec].push(node.run(@instance))
24
+ end
25
+ end
26
+ rescue
27
+ if is_safely
28
+ raise "An error has occured"
29
+ end
30
+ end
31
+ after_exec(@instance, @total_time)
32
+ @total_time
33
+ end
34
+
35
+ def draw_block(graph)
36
+ graph.hexagon << graph.node(id)
37
+ graph.node(id).label(name + 'Concurrently: ' + is_concurrently.to_s + '\nSafely: ' + is_safely.to_s)
38
+ end
39
+
40
+ end
@@ -3,7 +3,7 @@ require 'awesome_print'
3
3
 
4
4
  class Node
5
5
  attr_accessor :parent, :code_block, :is_safely, :node_list,
6
- :before_list, :after_list, :is_asynchronously,
6
+ :before_list, :after_list, :is_concurrently, :is_safely,
7
7
  :exec_block, :commands, :name, :id
8
8
 
9
9
  def initialize(parent, block)
@@ -13,7 +13,7 @@ class Node
13
13
  self.before_list = Array.new
14
14
  self.after_list = Array.new
15
15
  self.is_safely = false
16
- self.is_asynchronously = false
16
+ self.is_concurrently = false
17
17
  self.commands = Array.new
18
18
  self.id = self.to_s
19
19
  self.name = '[Node]'
@@ -72,7 +72,7 @@ class Node
72
72
 
73
73
  def draw_before_blocks(node, graph)
74
74
  if node.before_list.length > 0
75
- id = Random.rand(100000000000000000000000)
75
+ id = Random.rand(2**64)
76
76
  name = "[BEFORE]\n"
77
77
  node.before_list.each do |before|
78
78
  name += ">#{before}\n"
@@ -85,7 +85,7 @@ class Node
85
85
 
86
86
  def draw_after_blocks(node, graph)
87
87
  if node.after_list.length > 0
88
- id = Random.rand(100000000000000000000000)
88
+ id = Random.rand(2**64)
89
89
  name = "[AFTER]\n"
90
90
  node.after_list.each do |after|
91
91
  name += ">#{after}\n"
@@ -5,7 +5,7 @@ class OnNode < Node
5
5
  def initialize (parent, instance, block)
6
6
  super(parent, block)
7
7
  self.instance = instance
8
- self.name = "[OnNode]\n" + instance
8
+ self.name = "[OnInstance]\n" + instance
9
9
  end
10
10
 
11
11
  def run(instance)
@@ -16,14 +16,12 @@ class OnNode < Node
16
16
  puts @instance
17
17
  @total_time[:exec].push(node.run(@instance))
18
18
  end
19
-
20
19
  after_exec(@instance, @total_time)
21
-
22
- return @total_time
20
+ @total_time
23
21
  end
24
22
 
25
23
  def draw_block(graph)
26
- graph.hexagon << graph.node(id)
24
+ graph.tripleoctagon << graph.node(id)
27
25
  graph.node(id).label(name)
28
26
  end
29
27
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claudius
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-12-17 00:00:00.000000000 Z
13
+ date: 2015-01-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -136,14 +136,15 @@ files:
136
136
  - examples/on_instance.rb
137
137
  - examples/ping.rb
138
138
  - examples/simple_program.rb
139
+ - examples/simple_program_2.rb
139
140
  - examples/specify_instances.rb
140
141
  - lib/remote_execution/cloud_provider.rb
141
142
  - lib/remote_execution/provider.rb
142
143
  - lib/remote_execution/virtual_machine.rb
143
144
  - lib/tree_building/claudius.rb
144
145
  - lib/tree_building/concurrent_node.rb
145
- - lib/tree_building/event_machine_play.rb
146
146
  - lib/tree_building/execution_node.rb
147
+ - lib/tree_building/foreach_node.rb
147
148
  - lib/tree_building/node.rb
148
149
  - lib/tree_building/on_node.rb
149
150
  - test/execution_test.rb
@@ -1,20 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- require 'rubygems'
4
- require 'eventmachine'
5
-
6
- class Server < EventMachine::Connection
7
- attr_accessor :options, :status
8
-
9
- def receive_data(data)
10
- puts "#{@status} -- #{data}"
11
- send_data("helo\n")
12
- end
13
- end
14
-
15
- EM.run do
16
- EM.start_server 'localhost', 8080, Server do |conn|
17
- conn.options = {:my => 'options'}
18
- conn.status = :OK
19
- end
20
- end