nuri 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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__