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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +12 -0
- data/CHANGELOG +146 -0
- data/Gemfile +3 -0
- data/LICENSE +28 -0
- data/README.md +64 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/bin/delete_modules +11 -0
- data/bin/install_agent +18 -0
- data/bin/install_module +65 -0
- data/bin/nuri +519 -0
- data/bin/nuri.old +183 -0
- data/bin/push_model +16 -0
- data/examples/.gitignore +3 -0
- data/examples/bonfire.sfp +95 -0
- data/examples/bonfire/epcc.sfp +43 -0
- data/examples/bonfire/epcc0.sfp +49 -0
- data/examples/bonfire/epcc2.sfp +52 -0
- data/examples/bonfire/epcc2a.sfp +25 -0
- data/examples/bonfire/inria.sfp +72 -0
- data/examples/bonfire/inria0.sfp +49 -0
- data/examples/bonfire/inria2.sfp +71 -0
- data/examples/bonfire/inria2a.sfp +44 -0
- data/examples/bonfire/inria2b.sfp +54 -0
- data/examples/bonfire/inria2c.sfp +62 -0
- data/examples/bonfire/inria2d.sfp +71 -0
- data/examples/bonfire/inria2e.sfp +80 -0
- data/examples/bonfire/main.sfp +33 -0
- data/examples/bonfire/old/bonfire-1-1-1.sfp +76 -0
- data/examples/bonfire/old/bonfire-1-10-1.sfp +77 -0
- data/examples/bonfire/old/bonfire-1-2-1.sfp +58 -0
- data/examples/bonfire/old/bonfire-1-3-1.sfp +61 -0
- data/examples/bonfire/old/bonfire-1-4-1.sfp +64 -0
- data/examples/bonfire/old/bonfire-1-5-1.sfp +67 -0
- data/examples/bonfire/old/bonfire-1-6-1.sfp +82 -0
- data/examples/bonfire/old/bonfire-1-7-1.sfp +82 -0
- data/examples/bonfire/old/bonfire-1-8-1.sfp +79 -0
- data/examples/bonfire/old/bonfire-1-9-1.sfp +83 -0
- data/examples/bonfire/old/wp-test1a.sfp +38 -0
- data/examples/bonfire/old/wp-test1b.sfp +18 -0
- data/examples/bonfire/old/wp-test1c.sfp +7 -0
- data/examples/bonfire/old/wp-test2.sfp +47 -0
- data/examples/bonfire/old3/bonfire-epcc.sfp +57 -0
- data/examples/bonfire/old3/bonfire-inria.sfp +72 -0
- data/examples/bonfire/old3/bonfire-master.sfp +18 -0
- data/examples/bonfire/old3/bonfire.sfp +23 -0
- data/examples/bonfire/old3/bonfire2.sfp +49 -0
- data/examples/bonfire/old3/bonfire3.sfp +76 -0
- data/examples/bonfire/old3/bonfire4.sfp +78 -0
- data/examples/bonfire/old3/bonfire5.sfp +34 -0
- data/examples/bonfire/old3/bonfire5b.sfp +84 -0
- data/examples/bonfire/old3/hpvm6.sfp +22 -0
- data/examples/bonfire/old3/model.json +1 -0
- data/examples/bonfire/old3/test0.sfp +16 -0
- data/examples/bonfire/old3/test1.sfp +5 -0
- data/examples/bonfire/old3/test10.sfp +5 -0
- data/examples/bonfire/old3/test2.sfp +18 -0
- data/examples/bonfire/old3/test3.sfp +10 -0
- data/examples/bonfire/old3/test4.sfp +11 -0
- data/examples/bonfire/old3/test5.sfp +18 -0
- data/examples/bonfire/old3/test6.sfp +19 -0
- data/examples/bonfire/old3/test7.sfp +34 -0
- data/examples/bonfire/old3/test8.sfp +5 -0
- data/examples/bonfire/old3/test9.sfp +16 -0
- data/examples/bonfire/old3/wordpress-test-cluster.sfp +38 -0
- data/examples/bonfire/old3/wordpress-test.sfp +22 -0
- data/examples/bonfire/old3/wp-test-2.sfp +49 -0
- data/examples/bonfire/test.sfp +13 -0
- data/examples/generator.rb +66 -0
- data/examples/hadoop2.sfp +20 -0
- data/examples/hpcloud.sfp +18 -0
- data/examples/run.rb +17 -0
- data/examples/test.inc +0 -0
- data/examples/test.sfp +11 -0
- data/lib/naas/d3.js +5 -0
- data/lib/naas/d3.v3.min.js +5 -0
- data/lib/naas/index.css +0 -0
- data/lib/naas/index.html +18 -0
- data/lib/naas/index.js +18 -0
- data/lib/naas/jquery-1.10.2.min.js +6 -0
- data/lib/naas/jquery.js +6 -0
- data/lib/naas/naas.rb +160 -0
- data/lib/nuri.rb +62 -0
- data/lib/nuri/choreographer.rb +151 -0
- data/lib/nuri/constraint_helper.rb +9 -0
- data/lib/nuri/directory.rb +40 -0
- data/lib/nuri/master.rb +725 -0
- data/lib/nuri/net_helper.rb +65 -0
- data/lib/nuri/orchestrator.rb +224 -0
- data/lib/nuri/server.rb +212 -0
- data/modules/.gitignore +4 -0
- data/modules/apache/apache.rb +255 -0
- data/modules/apache/apache.rb.old +167 -0
- data/modules/apache/apache.sfp +146 -0
- data/modules/apache/apache.sfp.future +100 -0
- data/modules/apache/load_balancer +20 -0
- data/modules/apache/model.json +1 -0
- data/modules/apache/test.sfp +8 -0
- data/modules/aptpackage/aptpackage.rb +82 -0
- data/modules/aptpackage/aptpackage.sfp +5 -0
- data/modules/bonfire/.gitignore +2 -0
- data/modules/bonfire/README.md +12 -0
- data/modules/bonfire/bonfire.rb +60 -0
- data/modules/bonfire/bonfire.sfp +9 -0
- data/modules/bonfire/config.yml +4 -0
- data/modules/bonfire/helper.rb +149 -0
- data/modules/bonfire/stresstest.rb +144 -0
- data/modules/bonfire/test.sfp +8 -0
- data/modules/client/client.rb +22 -0
- data/modules/client/client.sfp +14 -0
- data/modules/cloud/cloud.rb +11 -0
- data/modules/cloud/cloud.sfp +26 -0
- data/modules/file/file.rb +91 -0
- data/modules/file/file.sfp +9 -0
- data/modules/hadoop1/core-site.xml +17 -0
- data/modules/hadoop1/hadoop-env.sh +55 -0
- data/modules/hadoop1/hadoop1.rb +384 -0
- data/modules/hadoop1/hadoop1.sfp +93 -0
- data/modules/hadoop1/hdfs-site.xml +16 -0
- data/modules/hadoop1/mapred-site.xml +17 -0
- data/modules/hadoop2/core-site.xml +31 -0
- data/modules/hadoop2/hadoop-env.sh +77 -0
- data/modules/hadoop2/hadoop2.rb +401 -0
- data/modules/hadoop2/hadoop2.sfp +114 -0
- data/modules/hadoop2/hdfs-site.xml +47 -0
- data/modules/hadoop2/mapred-site.xml +71 -0
- data/modules/hadoop2/ports +14 -0
- data/modules/hadoop2/yarn-env.sh +112 -0
- data/modules/hadoop2/yarn-site.xml +107 -0
- data/modules/hpcloud/.gitignore +2 -0
- data/modules/hpcloud/README.md +16 -0
- data/modules/hpcloud/config.yml +3 -0
- data/modules/hpcloud/example.sfp +18 -0
- data/modules/hpcloud/hpcloud.rb +241 -0
- data/modules/hpcloud/hpcloud.sfp +22 -0
- data/modules/hpcloud/test.sfp +5 -0
- data/modules/install_module +65 -0
- data/modules/machine/machine.rb +95 -0
- data/modules/machine/machine.sfp +9 -0
- data/modules/mockcloud/mockcloud.rb +20 -0
- data/modules/mockcloud/mockcloud.sfp +6 -0
- data/modules/mysql/mysql.rb +118 -0
- data/modules/mysql/mysql.sfp +38 -0
- data/modules/mysql/test.sfp +3 -0
- data/modules/node/node.rb +8 -0
- data/modules/node/node.sfp +7 -0
- data/modules/object/object.rb +7 -0
- data/modules/object/object.sfp +1 -0
- data/modules/os/os.rb +38 -0
- data/modules/os/os.sfp +11 -0
- data/modules/package/package.rb +26 -0
- data/modules/package/package.sfp +22 -0
- data/modules/package/test.sfp +6 -0
- data/modules/service/model.json +1 -0
- data/modules/service/service.rb +50 -0
- data/modules/service/service.sfp +46 -0
- data/modules/service/test.sfp +6 -0
- data/modules/tarpackage/tarpackage.rb +93 -0
- data/modules/tarpackage/tarpackage.sfp +5 -0
- data/modules/vm/vm.rb +8 -0
- data/modules/vm/vm.sfp +18 -0
- data/modules/wordpress/wordpress.rb +98 -0
- data/modules/wordpress/wordpress.sfp +34 -0
- data/modules/wordpresscluster/wordpresscluster.rb +150 -0
- data/modules/wordpresscluster/wordpresscluster.sfp +74 -0
- data/nuri.gemspec +26 -0
- 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/.travis.yml
ADDED
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
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
|
+
[](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
|
data/bin/delete_modules
ADDED
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
|
+
|
data/bin/install_module
ADDED
|
@@ -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__
|