nuri 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +12 -0
  4. data/CHANGELOG +146 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +28 -0
  7. data/README.md +64 -0
  8. data/Rakefile +15 -0
  9. data/VERSION +1 -0
  10. data/bin/delete_modules +11 -0
  11. data/bin/install_agent +18 -0
  12. data/bin/install_module +65 -0
  13. data/bin/nuri +519 -0
  14. data/bin/nuri.old +183 -0
  15. data/bin/push_model +16 -0
  16. data/examples/.gitignore +3 -0
  17. data/examples/bonfire.sfp +95 -0
  18. data/examples/bonfire/epcc.sfp +43 -0
  19. data/examples/bonfire/epcc0.sfp +49 -0
  20. data/examples/bonfire/epcc2.sfp +52 -0
  21. data/examples/bonfire/epcc2a.sfp +25 -0
  22. data/examples/bonfire/inria.sfp +72 -0
  23. data/examples/bonfire/inria0.sfp +49 -0
  24. data/examples/bonfire/inria2.sfp +71 -0
  25. data/examples/bonfire/inria2a.sfp +44 -0
  26. data/examples/bonfire/inria2b.sfp +54 -0
  27. data/examples/bonfire/inria2c.sfp +62 -0
  28. data/examples/bonfire/inria2d.sfp +71 -0
  29. data/examples/bonfire/inria2e.sfp +80 -0
  30. data/examples/bonfire/main.sfp +33 -0
  31. data/examples/bonfire/old/bonfire-1-1-1.sfp +76 -0
  32. data/examples/bonfire/old/bonfire-1-10-1.sfp +77 -0
  33. data/examples/bonfire/old/bonfire-1-2-1.sfp +58 -0
  34. data/examples/bonfire/old/bonfire-1-3-1.sfp +61 -0
  35. data/examples/bonfire/old/bonfire-1-4-1.sfp +64 -0
  36. data/examples/bonfire/old/bonfire-1-5-1.sfp +67 -0
  37. data/examples/bonfire/old/bonfire-1-6-1.sfp +82 -0
  38. data/examples/bonfire/old/bonfire-1-7-1.sfp +82 -0
  39. data/examples/bonfire/old/bonfire-1-8-1.sfp +79 -0
  40. data/examples/bonfire/old/bonfire-1-9-1.sfp +83 -0
  41. data/examples/bonfire/old/wp-test1a.sfp +38 -0
  42. data/examples/bonfire/old/wp-test1b.sfp +18 -0
  43. data/examples/bonfire/old/wp-test1c.sfp +7 -0
  44. data/examples/bonfire/old/wp-test2.sfp +47 -0
  45. data/examples/bonfire/old3/bonfire-epcc.sfp +57 -0
  46. data/examples/bonfire/old3/bonfire-inria.sfp +72 -0
  47. data/examples/bonfire/old3/bonfire-master.sfp +18 -0
  48. data/examples/bonfire/old3/bonfire.sfp +23 -0
  49. data/examples/bonfire/old3/bonfire2.sfp +49 -0
  50. data/examples/bonfire/old3/bonfire3.sfp +76 -0
  51. data/examples/bonfire/old3/bonfire4.sfp +78 -0
  52. data/examples/bonfire/old3/bonfire5.sfp +34 -0
  53. data/examples/bonfire/old3/bonfire5b.sfp +84 -0
  54. data/examples/bonfire/old3/hpvm6.sfp +22 -0
  55. data/examples/bonfire/old3/model.json +1 -0
  56. data/examples/bonfire/old3/test0.sfp +16 -0
  57. data/examples/bonfire/old3/test1.sfp +5 -0
  58. data/examples/bonfire/old3/test10.sfp +5 -0
  59. data/examples/bonfire/old3/test2.sfp +18 -0
  60. data/examples/bonfire/old3/test3.sfp +10 -0
  61. data/examples/bonfire/old3/test4.sfp +11 -0
  62. data/examples/bonfire/old3/test5.sfp +18 -0
  63. data/examples/bonfire/old3/test6.sfp +19 -0
  64. data/examples/bonfire/old3/test7.sfp +34 -0
  65. data/examples/bonfire/old3/test8.sfp +5 -0
  66. data/examples/bonfire/old3/test9.sfp +16 -0
  67. data/examples/bonfire/old3/wordpress-test-cluster.sfp +38 -0
  68. data/examples/bonfire/old3/wordpress-test.sfp +22 -0
  69. data/examples/bonfire/old3/wp-test-2.sfp +49 -0
  70. data/examples/bonfire/test.sfp +13 -0
  71. data/examples/generator.rb +66 -0
  72. data/examples/hadoop2.sfp +20 -0
  73. data/examples/hpcloud.sfp +18 -0
  74. data/examples/run.rb +17 -0
  75. data/examples/test.inc +0 -0
  76. data/examples/test.sfp +11 -0
  77. data/lib/naas/d3.js +5 -0
  78. data/lib/naas/d3.v3.min.js +5 -0
  79. data/lib/naas/index.css +0 -0
  80. data/lib/naas/index.html +18 -0
  81. data/lib/naas/index.js +18 -0
  82. data/lib/naas/jquery-1.10.2.min.js +6 -0
  83. data/lib/naas/jquery.js +6 -0
  84. data/lib/naas/naas.rb +160 -0
  85. data/lib/nuri.rb +62 -0
  86. data/lib/nuri/choreographer.rb +151 -0
  87. data/lib/nuri/constraint_helper.rb +9 -0
  88. data/lib/nuri/directory.rb +40 -0
  89. data/lib/nuri/master.rb +725 -0
  90. data/lib/nuri/net_helper.rb +65 -0
  91. data/lib/nuri/orchestrator.rb +224 -0
  92. data/lib/nuri/server.rb +212 -0
  93. data/modules/.gitignore +4 -0
  94. data/modules/apache/apache.rb +255 -0
  95. data/modules/apache/apache.rb.old +167 -0
  96. data/modules/apache/apache.sfp +146 -0
  97. data/modules/apache/apache.sfp.future +100 -0
  98. data/modules/apache/load_balancer +20 -0
  99. data/modules/apache/model.json +1 -0
  100. data/modules/apache/test.sfp +8 -0
  101. data/modules/aptpackage/aptpackage.rb +82 -0
  102. data/modules/aptpackage/aptpackage.sfp +5 -0
  103. data/modules/bonfire/.gitignore +2 -0
  104. data/modules/bonfire/README.md +12 -0
  105. data/modules/bonfire/bonfire.rb +60 -0
  106. data/modules/bonfire/bonfire.sfp +9 -0
  107. data/modules/bonfire/config.yml +4 -0
  108. data/modules/bonfire/helper.rb +149 -0
  109. data/modules/bonfire/stresstest.rb +144 -0
  110. data/modules/bonfire/test.sfp +8 -0
  111. data/modules/client/client.rb +22 -0
  112. data/modules/client/client.sfp +14 -0
  113. data/modules/cloud/cloud.rb +11 -0
  114. data/modules/cloud/cloud.sfp +26 -0
  115. data/modules/file/file.rb +91 -0
  116. data/modules/file/file.sfp +9 -0
  117. data/modules/hadoop1/core-site.xml +17 -0
  118. data/modules/hadoop1/hadoop-env.sh +55 -0
  119. data/modules/hadoop1/hadoop1.rb +384 -0
  120. data/modules/hadoop1/hadoop1.sfp +93 -0
  121. data/modules/hadoop1/hdfs-site.xml +16 -0
  122. data/modules/hadoop1/mapred-site.xml +17 -0
  123. data/modules/hadoop2/core-site.xml +31 -0
  124. data/modules/hadoop2/hadoop-env.sh +77 -0
  125. data/modules/hadoop2/hadoop2.rb +401 -0
  126. data/modules/hadoop2/hadoop2.sfp +114 -0
  127. data/modules/hadoop2/hdfs-site.xml +47 -0
  128. data/modules/hadoop2/mapred-site.xml +71 -0
  129. data/modules/hadoop2/ports +14 -0
  130. data/modules/hadoop2/yarn-env.sh +112 -0
  131. data/modules/hadoop2/yarn-site.xml +107 -0
  132. data/modules/hpcloud/.gitignore +2 -0
  133. data/modules/hpcloud/README.md +16 -0
  134. data/modules/hpcloud/config.yml +3 -0
  135. data/modules/hpcloud/example.sfp +18 -0
  136. data/modules/hpcloud/hpcloud.rb +241 -0
  137. data/modules/hpcloud/hpcloud.sfp +22 -0
  138. data/modules/hpcloud/test.sfp +5 -0
  139. data/modules/install_module +65 -0
  140. data/modules/machine/machine.rb +95 -0
  141. data/modules/machine/machine.sfp +9 -0
  142. data/modules/mockcloud/mockcloud.rb +20 -0
  143. data/modules/mockcloud/mockcloud.sfp +6 -0
  144. data/modules/mysql/mysql.rb +118 -0
  145. data/modules/mysql/mysql.sfp +38 -0
  146. data/modules/mysql/test.sfp +3 -0
  147. data/modules/node/node.rb +8 -0
  148. data/modules/node/node.sfp +7 -0
  149. data/modules/object/object.rb +7 -0
  150. data/modules/object/object.sfp +1 -0
  151. data/modules/os/os.rb +38 -0
  152. data/modules/os/os.sfp +11 -0
  153. data/modules/package/package.rb +26 -0
  154. data/modules/package/package.sfp +22 -0
  155. data/modules/package/test.sfp +6 -0
  156. data/modules/service/model.json +1 -0
  157. data/modules/service/service.rb +50 -0
  158. data/modules/service/service.sfp +46 -0
  159. data/modules/service/test.sfp +6 -0
  160. data/modules/tarpackage/tarpackage.rb +93 -0
  161. data/modules/tarpackage/tarpackage.sfp +5 -0
  162. data/modules/vm/vm.rb +8 -0
  163. data/modules/vm/vm.sfp +18 -0
  164. data/modules/wordpress/wordpress.rb +98 -0
  165. data/modules/wordpress/wordpress.sfp +34 -0
  166. data/modules/wordpresscluster/wordpresscluster.rb +150 -0
  167. data/modules/wordpresscluster/wordpresscluster.sfp +74 -0
  168. data/nuri.gemspec +26 -0
  169. metadata +281 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d02365a26a71b3202e77accdc43826f5da8c63ca
4
+ data.tar.gz: 00b72bf869f9802a32fe1bc4a2f4b350ffb889d2
5
+ SHA512:
6
+ metadata.gz: 63f4c79c68d7e624ec3ac944fdb7445edd8a78ee5370122c5133e4c24c2fe7d998ed01900ccd7a3c4bd0315ab33d4005473b8f13a8d0db0dae1c26ff028ed7fe
7
+ data.tar.gz: ee932dd09a18574c7ec58c9f55ca21a2085bad5be3be735d90de26be4610e599106a40eb273168db60834647b7e308b035c619fd5ba0fef6056b94ecdd3d627e
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.swp
3
+ *.pem
4
+ *.DS_Store
5
+ var
6
+ etc
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+
3
+ gemfile:
4
+ - Gemfile
5
+
6
+ rvm:
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - 2.0.0
10
+
11
+ notifications:
12
+ - email: false
data/CHANGELOG ADDED
@@ -0,0 +1,146 @@
1
+ 14-08-2013 -- 0.4.0
2
+ + upload 0.4.0 branch to github
3
+
4
+ 27-05-2013 -- 0.3.6
5
+ + update BSig engine with version 2
6
+
7
+ 26-04-2013 -- 0.3.5
8
+ + SFP: replace class with schema
9
+
10
+ 05-04-2013 -- 0.3.4
11
+ + enable standalone mode
12
+ + enable master node to apply desired state specified in given configuration file
13
+
14
+ 05-04-2013 -- 0.3.4(alpha)
15
+ + add new modules: nginx and mariadb
16
+ + replace nohup with forever in nurilabs
17
+ + add v init script "bin/nuri-init"
18
+ + modify "bin/install-client" to install v init script to enable
19
+ start/stop nuri-client deamon through "service"
20
+
21
+ 05-04-2013 -- 0.3.3
22
+ + add new modules "nurilabs" and "mongodb"
23
+
24
+ 06-03-2013 -- 0.3.2
25
+ + set the state of an "offline" node with <sfp::unknown> value
26
+
27
+ 28-02-2013 -- 0.3.2
28
+ + rename files in bin directory
29
+ + bin/nuri.rb => bin/nuri
30
+ + bin/client => bin/nuri-client
31
+ + bin/master => bin/nuri-master
32
+ + bin/bsig-status.sh => bin/bsig-status
33
+ + bin/install.sh => bin/install-client
34
+ + Add a new module "rackspace" that manages Rackspace Compute V2 (Next-Gen)
35
+ + Add a new module "aws" that manages Amazon Web Service EC2 (compute)
36
+
37
+ 25-02-2013 -- 0.3.1
38
+ + Fix a bug on the planner when a variable's initial value equals <sfp::unknown>.
39
+ This is fixed by adding <sfp::unknown> to domain of all non-static variables.
40
+
41
+ 18-02-2013 -- 0.3.1
42
+ + send a BSig-goal to a node that supports the goal
43
+ + the BSig-goal of uncreated VM will be sent to cloud-proxy, which will be
44
+ sent to Nuri client-agent after the VM has been created
45
+ + activate BSig model of a new-created VM after it received the BSig model
46
+ + a node with "null" address means that it is a VM but not yet created
47
+ + if a Nuri client-agent cannot be contacted, then all variables of that agent
48
+ have values "<sfp::unknown>"
49
+ + a variable has value "<sfp::undefined>" iff the node has been created,
50
+ the Nuri client-agent can be contacted, and the variable is not exist in
51
+ that node
52
+ + BSig-goal is a collection of pairs of variable-value, where variable's final
53
+ value is either not same with the initial state, or supported by an operator
54
+ in the workflow
55
+
56
+ 11-02-2013 -- 0.3.0a
57
+ + add the cloud-proxy node as "trusted" node -- inside "create_vm"
58
+ + enable system-information propagation between children nodes
59
+ + planner optimization
60
+ + run 1st with CG|CEA|FF to generate highly likely possible actions
61
+ + remove actions which are not selected by previous step
62
+ + run LMCUT with selected actions to get sub-optimal workflow
63
+
64
+ 10-02-2013 -- 0.3.0a
65
+ + enable machine's reference in members of Apachelb
66
+
67
+ 08-02-2013 -- 0.3.0
68
+ + enable cloud-proxy as a component, but right now only support HP-Cloud
69
+ + cloud-proxy is not integrated anymore with master-node
70
+ + new configuration in nuri.sfp: "virtual_machine" (boolean)
71
+ represents whether a node is a virtual machine or not; if it is, then use VM instead of Machine class
72
+ + update "get_system_information" method in master.rb to adopt cloud-proxy
73
+ + class VM is a subclass of class Machine in both SFP and Ruby codes
74
+
75
+ 09-01-2013 -- 0.2.1
76
+ + set time limit for the solver (default 5mins) -- it can be set by specifying "solver_timeout"
77
+ in "nuri.sfp"
78
+ + prioritise repairing local-flaws than remote-flaws
79
+ + rename method "get_self_state" => "update_state" in resource.rb and all modules' ruby files
80
+
81
+ 07-01-2013 -- 0.2.1
82
+ + new module: cloud (only handle HPCloud)
83
+ + create/delete Virtual Machine (VM)
84
+ + allow "parent" to be used in reference of constraint or mutation
85
+ + obligation to provide manifest file (main.mf) for non-abstract module
86
+ + any module without manifest file is an abstract module
87
+ (it will not loaded by Nuri when aggregating current state)
88
+
89
+ 02-01-2013 -- 0.2.0
90
+ + fix bugs in 'lib/nuri/sfp/sas.rb' -- in remove_not_constraint method
91
+ + enable multiple statements in conditional constraint
92
+ + allow administrator to check BSig status
93
+ + push trusted nodes from master to client
94
+ + restrict request only from trusted nodes in client
95
+ + allow client to expose its active BSig model
96
+
97
+ 27-12-2012 -- 0.2.0 (beta1)
98
+ + fix bugs on BSig reminder -- send start BSig request through localhost
99
+ + provide HTTP PUT /bsig/start -- to accept request starting BSig executor
100
+ + fix partial-order workflow generator (use TO2PO algorithm in Ambite & Knoblock,
101
+ Planning by Rewriting (2001) to replace Veloso et.al.'s algorithm(1990))
102
+ + provide new console command: console start-bsig
103
+ + fix bugs on repairing local-flaws: need to check post-conditions of every
104
+ operator execution with the real current state
105
+ + bin/nuri.rb can be called from any directory
106
+
107
+ 24-12-2012 -- 0.2.0 (beta)
108
+ + enable synchronous BSig execution (replacing the asynchronous version)
109
+ + redirect webrick logs (all levels) to "log/http.log"
110
+
111
+ 23-12-2012
112
+ + enable BSig executor to send request to itself (localhost) for satisfying an operator's precondition
113
+ + fix bugs on start/stop nuri client
114
+
115
+ 21-12-2012 -- 0.2.0 (alpha)
116
+ + enable distributed execution, but only tested on a system with 3 nodes
117
+
118
+ 19-12-2012 -- 0.1.4
119
+ + from master node, sending BSig model to each client nodes
120
+ + on client node, saving the BSig model
121
+
122
+ 18-12-2012 -- 0.1.3
123
+ + enable partial-order workflow
124
+ + generate BSig model
125
+ + modify CLI parameters in 'bin/nuri.rb'
126
+ -c => console
127
+ -p => planner
128
+
129
+ 12-12-2012 -- 0.1.2
130
+ + replace mongrel with WEBrick
131
+ + disable secure connection due to immature implementations (buggy)
132
+
133
+ 18-11-2012 -- 0.1.1
134
+ + implement modules to manage TikiWiki; separated into two modules:
135
+ - Tikiweb -- managing the frontend: installing PHP files, set PHP config
136
+ - Tikidb -- managing the backend: executing SQL to create the database, grant/revoke permissions
137
+
138
+ 12-11-2012
139
+ + implement module "Apachelb" -- Apache Load Balancer
140
+ + allow Set as argument of procedure
141
+
142
+ 06-11-2012
143
+ + first release
144
+ + available modules
145
+ - Apache
146
+ - Mysql
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD LICENSE
2
+
3
+ Copyright (c) 2013, Herry
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ The views and conclusions contained in the software and documentation are those
27
+ of the authors and should not be interpreted as representing official policies,
28
+ either expressed or implied, of the FreeBSD Project.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ Nuri
2
+ ====
3
+ - author: Herry [herry13@gmail.com]
4
+ - license: BSD
5
+
6
+ [![Gem Version](https://badge.fury.io/rb/nuri.png)](https://badge.fury.io/rb/nuri)
7
+
8
+ Nuri is an automated workflow configuration tool. It allows us to define the desired state of
9
+ the managed system, and the tool will automatically generate and orchestrate the execution of the workflow
10
+ that will:
11
+
12
+ 1. bring the system from current to the desired state,
13
+ 2. maintain any necessary constraints during the configuration changes.
14
+
15
+ Unlike any other orchestration tool, this will eliminate the obligation for the user to define an explicit
16
+ workflow to implement the configuration, which allows "unattended" reconfiguration.
17
+
18
+ The desired state is specified in a declarative configuration language, called as SFP, where we could
19
+ define a "loose" specification of the desired state as well as a set of global constraints
20
+ (the constraints that must be satisfied during the changes).
21
+
22
+ Each resource is managed by an instant of Nuri module, which consists of:
23
+
24
+ 1. a schema file in SFP language, that contains a set of attributes and declarative procedures;
25
+ 2. an implementation file in Ruby, that has contains a Ruby class with a set of methods (the implementation of SFP procedures).
26
+
27
+
28
+ Requirements
29
+ ------------
30
+ - Ruby (>= 1.9.1)
31
+ - Ruby Gems:
32
+ - sfplanner (>= 0.1.1)
33
+ - colorize (>= 0.5.8)
34
+ - coderay (>= 1.0.9)
35
+
36
+ Tested on: **Ubuntu 12.04**, **Debian Squeeze**
37
+
38
+
39
+ To install
40
+ ----------
41
+
42
+ $ apt-get install git make gcc curl ruby1.9.1 ruby1.9.1-dev libz-dev libaugeas-ruby1.9.1 libxml2-dev libxslt-dev
43
+ $ gem install sfplanner colorize coderay
44
+ $ git clone https://github.com/herry13/nuri
45
+
46
+
47
+ Usage
48
+ -----
49
+ Assume that the model of your system is in file "model.sfp".
50
+ - to get the current state
51
+
52
+ $ ./bin/nuri -h -m model.sfp -s
53
+
54
+ - to generate the plan
55
+
56
+ $ ./bin/nuri -h -m model.sfp -p
57
+
58
+ press 'Y' and enter to execute the plan (if the plan exists).
59
+
60
+ - to execute any generated plan
61
+
62
+ $ ./bin/nuri -h -m model.sfp -a
63
+
64
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ def nuri
2
+ File.dirname(__FILE__) + '/bin/nuri'
3
+ end
4
+
5
+ def testfiles
6
+ File.read(File.dirname(__FILE__) + "/test/files").split("\n")
7
+ end
8
+
9
+ task :default => :test
10
+
11
+ namespace :test do
12
+ testfiles.each { |file|
13
+ sh("#{nuri} model -m #{file}")
14
+ }
15
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ if [[ "$1" == "" ]]
4
+ then
5
+ echo "Usage: delete_modules <address> [port]"
6
+ elif [[ "$2" == "" ]]
7
+ then
8
+ curl -i -X PUT $1:1314/modules
9
+ else
10
+ curl -i -X PUT $1:$2/modules
11
+ fi
data/bin/install_agent ADDED
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ COMMANDS="apt-get update;
4
+ apt-get -y install sudo ruby ruby-dev rubygems libz-dev libaugeas-ruby make gcc libxml2-dev libxslt-dev libreadline-dev;
5
+ gem install sfp sfpagent fog restfully restfully-addons --no-ri --no-rdoc;
6
+ ln -sf /var/lib/gems/1.8/bin/sfpagent /usr/local/bin/sfpagent;
7
+ sfpagent -t;
8
+ sfpagent -s;
9
+ "
10
+
11
+ if [[ "$@" == "" ]]
12
+ then
13
+ echo "Usage: install_agent <ssh-parameters>"
14
+ else
15
+ echo $COMMANDS | ssh "$@"
16
+ fi
17
+
18
+
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+
3
+ DefaultPort=1314
4
+
5
+ # verify the arguments
6
+ if [[ "$1" == "" ]] || [[ "$2" == "" ]]; then
7
+ echo "Usage: install_module <address> [port] <module-name> ..."
8
+ exit 1
9
+ fi
10
+
11
+ # set the agent's address
12
+ address=$1
13
+ shift
14
+
15
+ # set the agent's port number
16
+ re='^[0-9]+$'
17
+ if [[ $1 =~ $re ]]; then
18
+ port=$1
19
+ shift
20
+ else
21
+ port=$DefaultPort
22
+ fi
23
+
24
+ # set a template command for sending the modules
25
+ cmd="curl -s -i -X PUT $address:$port/modules"
26
+
27
+ # setup directory for temporary files
28
+ dir="/tmp/"$(date +%s%N)"$RANDOM"
29
+ mkdir -p $dir
30
+
31
+ # for every module in the arguments:
32
+ # - archive the module's files to a temporary file
33
+ # - update the sending command by adding the module
34
+ # if the module is not exist then the program will
35
+ # set missing_module flag and then break from the loop
36
+ missing_module=0
37
+ for module in "$@" ; do
38
+ if [[ -d "$module" ]]; then
39
+ tar cvzhf $dir/$module.tgz $module 1>/dev/null
40
+ cmd="$cmd -F $module=@$dir/$module.tgz"
41
+ else
42
+ echo "Module $module is not exist!"
43
+ missing_module=`expr $missing_module + 1`
44
+ fi
45
+ done
46
+
47
+ if [[ $missing_module == 0 ]]; then
48
+ # execute the sending command there is no missing module
49
+ result=`$cmd`
50
+ re='.*HTTP/1\.1 200 OK.*'
51
+ if ! [[ $result =~ $re ]]; then
52
+ missing_module=`expr $missing_module + 1`
53
+ fi
54
+ fi
55
+
56
+ # delete directory that holds temporary files
57
+ rm -rf $dir
58
+
59
+ if [[ $missing_module == 0 ]]; then
60
+ echo "status: ok"
61
+ else
62
+ echo "status: failed"
63
+ fi
64
+
65
+ exit $missing_module
data/bin/nuri ADDED
@@ -0,0 +1,519 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ dir = File.expand_path('../../', __FILE__)
4
+ require "#{dir}/lib/nuri"
5
+
6
+ Version = File.read(File.dirname(__FILE__) + "/../VERSION").strip
7
+ About = "Nuri #{Version} (c) 2013"
8
+
9
+ HTTP = Object.new.extend(Nuri::Net::Helper)
10
+
11
+ Nuri.init
12
+
13
+ def console(*args)
14
+ print Time.now.strftime('%Y-%m-%d %H:%M:%S '.yellow)
15
+ $stdout.puts(args)
16
+ end
17
+
18
+ class Sfp::Console
19
+ PrettyStateGenerator = Sfp::Visitor::PrettyStateGenerator.new
20
+ ParentEliminator = Sfp::Visitor::ParentEliminator.new
21
+
22
+ def process_args(args, parser)
23
+ Trollop::with_standard_exception_handling parser do
24
+ parser.parse args
25
+ end
26
+ end
27
+
28
+ def check_help(args)
29
+ help = args.count { |x| x == '-h' or x == '--help' }
30
+ [(help > 0), args.select { |x| x != '-h' and x != '--help' }]
31
+ end
32
+
33
+ def do_state(args=ARGV, cmd="nuri ")
34
+ parser = Trollop::Parser.new do
35
+ banner <<-EOS
36
+ Usage: #{cmd}state [options]
37
+ where [options] are:
38
+ EOS
39
+ opt :model_file, 'file contains a model of desired state', :default => Nuri.main, :short => '-m'
40
+ opt :json, 'print output in JSON'
41
+ opt :plain, 'print output in plain text'
42
+ opt :no_push_module, 'disable automatic push module'
43
+ end
44
+ help, args = check_help(args)
45
+ opts = process_args args, parser
46
+
47
+ if help
48
+ parser.educate(STDOUT)
49
+
50
+ elsif File.exist?(opts[:model_file])
51
+ opts[:push_modules] = true if !opts[:no_push_module]
52
+ master = Nuri::Master.new
53
+ master.set_model opts
54
+ state = master.get_state opts
55
+ state.accept(Sfp::Helper::Sfp2Ruby)
56
+
57
+ if opts[:json]
58
+ puts (opts[:plain] ? JSON.generate(state) : CodeRay.encode(JSON.pretty_generate(state), :json, :terminal))
59
+ else
60
+ puts (opts[:plain] ? YAML.dump(state) : CodeRay.encode(YAML.dump(state), :yaml, :terminal))
61
+ end
62
+ else
63
+ $stderr.puts "Model file '#{opts[:model_file]}' is not exist! Use \"-h\" option for more details.".red
64
+
65
+ end
66
+ end
67
+
68
+ def do_plan(args=ARGV, cmd="nuri ")
69
+ parser = Trollop::Parser.new do
70
+ banner <<-EOS
71
+ Usage: #{cmd}plan [options]
72
+ where [options] are:
73
+ EOS
74
+ opt :model_file, 'file contains a model of desired state', :default => Nuri.main, :short => '-m'
75
+ opt :parallel, 'generate a parallel plan', :short => '-l'
76
+ opt :apply, 'generate and execute a plan', :short => '-a'
77
+ opt :plain, 'print output in plain JSON'
78
+ opt :no_interactive, 'disable interactive input'
79
+ opt :no_push_module, 'disable automatic push module'
80
+ end
81
+ help, args = check_help(args)
82
+ opts = process_args args, parser
83
+
84
+ if help
85
+ parser.educate(STDOUT)
86
+ elsif File.exist?(opts[:model_file])
87
+ opts[:plan] = true
88
+ opts[:push_modules] = true if !opts[:no_push_module]
89
+ master = Nuri::Master.new
90
+ master.set_model(opts)
91
+ plan = master.get_plan(opts)
92
+ if plan.is_a?(Hash) and !plan['workflow'].nil?
93
+ if plan['workflow'].length > 0
94
+ if opts[:plain]
95
+ puts JSON.generate(plan)
96
+ else
97
+ actions = plan['workflow']
98
+ if plan['type'] == 'sequential'
99
+ p = 'Sequential Plan:'.yellow
100
+ actions.each_index { |i| p += "\n#{i+1}. #{actions[i]['name']} #{JSON.generate(actions[i]['parameters'])}" }
101
+ puts p
102
+ else
103
+ p = 'Partial-Order Plan:'.yellow
104
+ actions.each { |op| p += "\n#{op['id']+1}. #{op['name']} #{JSON.generate(op['parameters'])} (#{op['predecessors'].map{|i|i+1}}, #{op['successors'].map{|i|i+1}})" }
105
+ puts p
106
+ end
107
+ end
108
+
109
+ if not opts[:apply] and not opts[:no_interactive]
110
+ print "Execute the plan [y/N]? "
111
+ opts[:apply] = true if STDIN.gets.chomp.upcase == 'Y'
112
+ end
113
+
114
+ if opts[:apply]
115
+ puts 'Executing the plan: '.yellow
116
+ opts[:plan] = plan
117
+ if master.execute_plan(opts)
118
+ puts "Execution success!".green
119
+ else
120
+ puts "Execution failed!".red
121
+ end
122
+ end
123
+ elsif plan['workflow'].length == 0
124
+ puts (opts[:plain] ? 'Goal state has been achieved.' : 'Goal state has been achieved.').green
125
+ end
126
+ else
127
+ $stderr.puts (opts[:plain] ? "No solution!".yellow : "No solution!".red)
128
+ end
129
+ else
130
+ $stderr.puts "Model file '#{opts[:model_file]}' is not exist! Use \"-h\" option for more details.".red
131
+ end
132
+ end
133
+
134
+ def do_bsig(args=ARGV, cmd="nuri ")
135
+ parser = Trollop::Parser.new do
136
+ banner <<-EOS
137
+ Usage: #{cmd}bsig [options]
138
+ where [options] are:
139
+ EOS
140
+ opt :model_file, 'file contains a model of desired state', :default => Nuri.main, :short => '-m'
141
+ opt :purge, 'purge existing BSig model', :short => '-g'
142
+ opt :deploy, 'generate and then deploy a BSig model'
143
+ opt :plain, 'print output in plain JSON'
144
+ opt :no_interactive, 'disable interactive input'
145
+ end
146
+ help, args = check_help(args)
147
+ opts = process_args args, parser
148
+
149
+ if help
150
+ parser.educate(STDOUT)
151
+ elsif File.exist?(opts[:model_file])
152
+ opts[:bsig_deploy] = true
153
+ opts[:parallel] = true
154
+ master = Nuri::Master.new
155
+ master.set_model(opts)
156
+
157
+ if opts[:purge]
158
+ if master.purge_bsig(opts)
159
+ puts "Purging Behavioural Signature model [OK]".green
160
+ else
161
+ puts "Purging Behavioural Signature model [Failed]".red
162
+ end
163
+ else
164
+ bsig = master.get_bsig(opts)
165
+ if bsig.is_a?(Hash) and bsig.length > 0
166
+ empty_local_bsig = bsig.select { |name,local_bsig| local_bsig['operators'].length <= 0 }
167
+ if empty_local_bsig.length != bsig.length
168
+ if opts[:plain]
169
+ puts JSON.generate(bsig)
170
+ else
171
+ puts CodeRay.encode(JSON.pretty_generate(bsig), :json, :terminal)
172
+ end
173
+
174
+ if not opts[:no_interactive] and not opts[:deploy]
175
+ print "Deploy the BSig model [y/N]? "
176
+ opts[:deploy] = true if STDIN.gets.chomp.upcase == 'Y'
177
+ end
178
+
179
+ if opts[:deploy]
180
+ puts 'Deploying the BSig model: '.yellow
181
+ opts[:bsig] = bsig
182
+ if master.deploy_bsig(opts)
183
+ puts "Deployment success!".green
184
+ else
185
+ puts "Deployment failed!".red
186
+ end
187
+ end
188
+ else
189
+ puts (opts[:plain] ? 'Goal state has been achieved.' : 'Goal state has been achieved.').green
190
+ end
191
+ else
192
+ $stderr.puts (opts[:plain] ? "No solution!".yellow : "No solution!".red)
193
+ end
194
+ end
195
+ else
196
+ $stderr.puts "Model file '#{opts[:model_file]}' is not exist! Use \"-h\" option for more details.".red
197
+ end
198
+ end
199
+
200
+ def do_agent(args=ARGV, cmd="nuri ")
201
+ parser = Trollop::Parser.new do
202
+ banner <<-EOS
203
+ Usage: #{cmd}agent <subcommand> [node] [options]
204
+ where <subcommand> is:
205
+ install install agent (use SSH for remote node)
206
+ upgrade upgrade agent (use SSH for remote node)
207
+ start start the agent (use SSH for remote node)
208
+ restart restart the agent (use SSH for remode node)
209
+ stop stop the agent (use SSH for remote node)
210
+ status get status (use SSH for remote node)
211
+ state get current state
212
+ model get current model
213
+ bsig get current Behavioural Signature model
214
+ exec <action> execute given action description
215
+ <action> = <path> [param1=value1 param2=value2 ...]
216
+ module get modules list
217
+ log get last 100 lines of logs
218
+ list list of available agents from model file
219
+
220
+ where [options] are:
221
+ EOS
222
+ opt :model_file, 'file contains a model of desired state', :default => Nuri.main, :short => '-m'
223
+ opt :address, "address", :default => 'localhost'
224
+ opt :port, "port", :default => 1314
225
+ opt :ssh_user, "SSH username", :short => '-u', :default => 'root'
226
+ opt :ssh_port, "SSH port", :short => '-p', :default => '22'
227
+ end
228
+ help, args = check_help(args)
229
+ subcommand = (args.length > 0 ? args.shift : '')
230
+ opts = process_args args, parser
231
+ ssh_opt = ''
232
+ if opts[:address] != 'localhost'
233
+ ssh_opt = "ssh "
234
+ ssh_opt += (opts[:ssh_user] ? "#{opts[:ssh_user]}@#{opts[:address]}" : opts[:address])
235
+ ssh_opt += (opts[:ssh_port] ? " -p #{opts[:ssh_port]}" : '')
236
+ end
237
+
238
+ if help
239
+ parser.educate(STDOUT)
240
+ elsif `which sfpagent`.strip.length > 0
241
+ case subcommand
242
+ when 'install'
243
+ system("#{ssh_opt} sudo gem install sfpagent --no-ri --no-rdoc")
244
+
245
+ when 'start'
246
+ system "#{ssh_opt} sfpagent -s && sleep 5"
247
+ system "#{ssh_opt} sfpagent -a"
248
+
249
+ when 'restart'
250
+ system "#{ssh_opt} sfpagent -r"
251
+
252
+ when 'stop'
253
+ system("#{ssh_opt} sfpagent -t")
254
+
255
+ when 'status'
256
+ system("#{ssh_opt} sfpagent -a")
257
+
258
+ when 'upgrade'
259
+ system("#{ssh_opt} sudo gem update sfpagent --no-ri --no-rdoc")
260
+
261
+ when 'state'
262
+ code, state = HTTP.get_data(opts[:address], 1314, "/state")
263
+ if code == '200' and state =~ /{.*}/
264
+ state = JSON[state]['state']
265
+ state.keys.each { |key| state.delete(key) if state[key]['_context'] != 'object' }
266
+ puts CodeRay.encode(JSON.pretty_generate(state), :json, :terminal)
267
+ else
268
+ puts state
269
+ end
270
+
271
+ when 'model'
272
+ code, model = HTTP.get_data(opts[:address], 1314, "/model")
273
+ if code == '200' and model =~ /{.*}/
274
+ model = JSON[model]
275
+ model.keys.each { |key| model.delete(key) if model[key]['_context'] != 'object' }
276
+ puts CodeRay.encode(JSON.pretty_generate(model), :json, :terminal)
277
+ else
278
+ puts model
279
+ end
280
+
281
+ when 'bsig'
282
+ code, json = HTTP.get_data(opts[:address], 1314, "/bsig")
283
+ puts (code == '200' and json.length >= 2 ? CodeRay.encode(JSON.pretty_generate(JSON[json]), :json, :terminal) : json)
284
+
285
+ when 'module'
286
+ code, json = HTTP.get_data(opts[:address], 1314, "/bsig")
287
+ puts (code == '200' and json.length >= 2 ? CodeRay.encode(JSON.pretty_generate(JSON[json]), :json, :terminal) : json)
288
+
289
+ when 'exec', 'execute'
290
+ if args.length > 0
291
+ name = args.shift
292
+ name = '$.' + name if !name.isref
293
+ parameters = {}
294
+ args.each do |arg|
295
+ if arg =~ /=/
296
+ arg = arg.split('=', 2)
297
+ parameters[arg[0]] = arg[1]
298
+ end
299
+ end
300
+ data = { 'action' => JSON.generate({ 'name' => name, 'parameters' => parameters }) }
301
+ code, _ = HTTP.post_data(opts[:address], 1314, "/execute", data)
302
+ puts (code == '200' ? "Executing #{name} [OK]".green : "Executing #{name} [Failed]".red)
303
+ else
304
+ $stderr.puts 'Invalid parameters (usage: agent exec <action-path> [action-arguments]).'
305
+ end
306
+
307
+ when 'log'
308
+ puts Net::HTTP.get "#{opts[:address]}", "/log", 1314
309
+
310
+ when 'list'
311
+ get_agents(opts).each { |name,model| puts "#{name} address=#{model['sfpAddress']} port=#{model['sfpPort']}" }
312
+
313
+ when 'help'
314
+ parser.educate(STDOUT)
315
+
316
+ else
317
+ $stderr.puts 'Unrecognized command! Use \"-h\" to print available commands.'.red
318
+ end
319
+ else
320
+ $stderr.puts 'sfpagent gem is not installed!'.red
321
+ end
322
+ end
323
+
324
+ def do_edit(args=ARGV)
325
+ file = (args[0].nil? ? Nuri.main : args[0].to_s)
326
+ if file == '-h' or file == '--help'
327
+ puts <<-EOS
328
+ Usage: edit <filepath>
329
+ EOS
330
+
331
+ elsif File.exist?(file)
332
+ system "#{Nuri.config['editor']} #{file}"
333
+
334
+ else
335
+ $stderr.puts 'Target file is not specified!'
336
+
337
+ end
338
+ end
339
+
340
+ def get_agents(opts={})
341
+ opts[:push_modules] = true if !opts[:no_push_module]
342
+ master = Nuri::Master.new
343
+ master.set_model opts
344
+ state = master.get_state opts
345
+ agents = {}
346
+ state.each do |name,model|
347
+ agents[name] = {
348
+ 'sfpAddress' => (model['sfpAddress'].is_a?(String) ? model['sfpAddress'] : ''),
349
+ 'sfpPort' => (model['sfpPort'].is_a?(Fixnum) ? model['sfpPort'] : 0)
350
+ }
351
+ end
352
+ agents
353
+ end
354
+
355
+ def do_console
356
+ banner = <<-EOS
357
+ Usage: <command> [options]
358
+ when <command> is:
359
+ state get current state
360
+ plan generate a plan
361
+ bsig deployment with distributed mechanism
362
+ agent manage Nuri agent
363
+ edit edit file
364
+ help print this help
365
+ exit exit this console
366
+
367
+ EOS
368
+
369
+ username = `whoami`.strip
370
+ puts About
371
+ loop do
372
+ begin
373
+ print "nuri@#{username}> ".green
374
+ begin
375
+ input = STDIN.gets
376
+ raise Exception if input.nil?
377
+ rescue Exception
378
+ puts ''
379
+ break
380
+ end
381
+ input = input.chomp.strip
382
+ if input.length <= 0
383
+ elsif input[0] == '!'
384
+ system(input[1..input.length])
385
+ else
386
+ command, args = input.split(' ', 2)
387
+ break if command == 'exit' or command == 'quit' or command == 'q'
388
+ args = args.to_s.split(' ')
389
+ command = args[0] and args = ['-h'] if command == 'help' and args.length > 0
390
+ case command
391
+ when 'state'
392
+ do_state args, ''
393
+ when 'plan'
394
+ do_plan args, ''
395
+ when 'bsig'
396
+ do_bsig args, ''
397
+ when 'agent'
398
+ do_agent args, ''
399
+ when 'edit'
400
+ do_edit args
401
+ when 'model'
402
+ do_model args
403
+ when 'cd'
404
+ Dir.chdir(args[0].to_s)
405
+ when 'pwd'
406
+ puts Dir.pwd
407
+ when 'ls'
408
+ system "ls --color #{args.join(" ")}"
409
+ when 'help'
410
+ puts banner
411
+ when 'version', '-v'
412
+ puts About
413
+ else
414
+ $stderr.puts 'Unrecognized command! Use \"-h\" option to print available commands.'.red
415
+ end
416
+ end
417
+ rescue Exception => e
418
+ $stderr.puts "#{e}\n#{e.backtrace.join("\n")}"
419
+ end
420
+ end
421
+ puts "Bye!\n"
422
+ end
423
+
424
+ def do_model(args=ARGV, cmd='nuri')
425
+ parser = Trollop::Parser.new do
426
+ banner <<-EOS
427
+ Usage: #{cmd}state [options]
428
+ where [options] are:
429
+ EOS
430
+ opt :model_file, 'file contains a model of desired state', :default => Nuri.main, :short => '-m'
431
+ opt :json, 'print output in JSON'
432
+ opt :plain, 'print output in plain format'
433
+ end
434
+ help, args = check_help(args)
435
+ opts = process_args args, parser
436
+
437
+ if help
438
+ parser.educate(STDOUT)
439
+
440
+ elsif File.exist?(opts[:model_file])
441
+ @parser = Sfp::Parser.new({:home_dir => File.dirname(opts[:model_file])})
442
+ @parser.parse File.read(opts[:model_file])
443
+ model = @parser.root
444
+ model.accept(ParentEliminator)
445
+ model.select! { |k,v| k[0,1] != '_' and (not v.is_a?(Hash) or v['_context'] == 'object') }
446
+ model.accept(Sfp::Helper::Sfp2Ruby)
447
+
448
+ if opts[:json]
449
+ puts (opts[:plain] ? JSON.generate(model) : CodeRay.encode(JSON.pretty_generate(model), :json, :terminal))
450
+ else
451
+ puts (opts[:plain] ? YAML.dump(model) : CodeRay.encode(YAML.dump(model), :yaml, :terminal))
452
+ end
453
+
454
+ else
455
+ $stderr.puts "Model file '#{opts[:model_file]}' is not exist! Use \"-h\" option for more details.".red
456
+
457
+ end
458
+
459
+ end
460
+
461
+ def run
462
+ banner = <<-EOS
463
+ Usage: nuri [command]
464
+ where [command] is:
465
+ model get compilation result of the model
466
+ state get the current state
467
+ plan generate the plan
468
+ bsig deployment with distributed mechanism
469
+ agent manage Nuri agent
470
+ console enter console
471
+
472
+ EOS
473
+
474
+ if ARGV.length > 0
475
+ success = false
476
+ case ARGV.shift
477
+ when 'state'
478
+ do_state
479
+ when 'plan'
480
+ do_plan
481
+ when 'bsig'
482
+ do_bsig
483
+ when 'agent'
484
+ do_agent
485
+ when 'console'
486
+ do_console
487
+ when 'edit'
488
+ do_edit
489
+ when 'model'
490
+ do_model
491
+ else
492
+ puts banner
493
+ end
494
+ else
495
+ puts banner
496
+ end
497
+ end
498
+ end
499
+
500
+ module Sfp::Helper
501
+ Sfp2Ruby = Object.new
502
+ def Sfp2Ruby.visit(name, value, parent)
503
+ if name[0] == '_'
504
+ parent.delete(name)
505
+ elsif value.is_a?(Hash)
506
+ case value['_context']
507
+ when 'null'
508
+ parent[name] = nil
509
+ when 'any_value', 'constraint', 'procedure'
510
+ parent.delete(name)
511
+ when 'set'
512
+ parent[name] = value['_values']
513
+ end
514
+ end
515
+ true
516
+ end
517
+ end
518
+
519
+ Sfp::Console.new.run if $0 == __FILE__