nuri 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![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
|
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__
|