-
Notifications
You must be signed in to change notification settings - Fork 0
Quick example
Let's build a quick and simple example even your boss will understand.
INV requires a good understanding of your existing ecosystem rules.
Our objective is to convert these rules into Groovy script files and let INV handle the rest for us.
- ServerA hosts AppA through Kubernetes
- ServerB hosts AppB through IIS
With these rules, we can determine:
- 6 INV's
- At least 4 statements (or link or broadcasts/requirements)
Groovy is the most-suitable framework for understandable, idiomatic and quick-time to market solutions.
INV adds a layer using the DSL features of Groovy.
For more information about the syntax of INV, read this.
Think of your INV's as individuals that are working together in a production chain.
Ask yourself "who does what" and "who tells what".
Bellow is a rendering of our previous example statements:
inv {
name "ServerA"
broadcast inv.Server using {
id name: "server-a"
ready {
return [
host: "10.22.99.999",
install: { service ->
println "Installing service ${service} on 10.22.99.999"
}
]
}
}
}
inv {
name "ServerB"
broadcast inv.Server using {
id name: "server-b"
ready {
return [
host: "10.22.99.998",
]
}
}
}
inv {
name "Kubernetes"
require inv.Server using {
id name: "server-a"
resolved {
assert response
response.install("kubectl")
}
}
broadcast inv.Kubernetes using {
ready {
return [
http : "http://my-kubernetes.my.host.com",
port : "8089", // not by default
installPod: { pod ->
println "Pod ${pod} has been installed"
}
]
}
}
}
inv {
name "appA"
require inv.Kubernetes using {
resolved {
response.installPod("my-mod-for-app-3")
}
}
}
inv {
name "iis"
require inv.Server(name: "server-a")
broadcast inv.IIS using {
ready {
return [
deploy: {webApp ->
println "IIS webapp ${webApp} has been deployed"
}
]
}
}
}
inv {
name "appB"
require inv.IIS using {
resolved {
response.deploy("my-web-app")
}
}
}
INV enable a more encapsulated ecosystem.
In this simple case, we managed to implement a solution who protects critical information.
In our case, appB
does not know which credentials or which host is used to deploy. Only ÌIS
knows.
INV comes with default implementations, such as "files (I/O), http, ..."
It serves mostly as concrete examples on how you could implement things, but you could use them in your ecosystem as well.
You can see them at here
You may use the command-line utility (see at the top for available commands).
You may also use the Web Platform named INV Composer for a more elegant and accompanied path.
Here's our example using the command-line utility:
inv load ./example/githubHomepage/*.groov
This command would generate the following output:
[INV] file: ./example/githubHomepage/appA.groovy
[INV] file: ./example/githubHomepage/appB.groovy
[INV] file: ./example/githubHomepage/iis.groovy
[INV] file: ./example/githubHomepage/kubernetes.groovy
[INV] file: ./example/githubHomepage/serverA.groovy
[INV] file: ./example/githubHomepage/serverB.groovy
[INV] ---- [DIGEST] started ----
[INV] ---- [DIGEST] #1 (state=RUNNING) ----
[INV] [ServerA] => [BROADCAST] [Server] [name:server-a]
[INV] [ServerB] => [BROADCAST] [Server] [name:server-b]
[INV] ---- [DIGEST] #2 (state=RUNNING) ----
[INV] [iis] => [REQUIRE] [Server] [name:server-a]
[INV] [iis] => [BROADCAST] [IIS] undefined
[INV] [Kubernetes] => [REQUIRE] [Server] [name:server-a]
[INV] [Kubernetes] => [BROADCAST] [Kubernetes] undefined
Installing service kubectl on 10.22.99.999
[INV] ---- [DIGEST] #3 (state=RUNNING) ----
[INV] [appA] => [REQUIRE] [Kubernetes] undefined
[INV] [appB] => [REQUIRE] [IIS] undefined
Pod my-mod-for-app-3 has been installed
IIS webapp my-web-app has been deployed
[INV] ---- [DIGEST] completed ----
By reading the output log, without having the fine details, we can determine:
- Who needs what
- Who says (or give) what
- More precisely, in our case, which instance server (barebone or under kubernetes) hosts AppA and etc.
INV output logs are human and "machine" readable.
In fact, you could also generate a graph from a previous execution.
NOTE: Output logs does not need to have exclusively INV messages, you may output messages to ease troubleshooting. INV only looks for lines starting with "[INV]".
So, continuing with out example, with our last execution (just above), using this command :
inv graph dot myprevious.log
Upon completion, we get a dot rendered output (see https://en.wikipedia.org/wiki/DOT_(graph_description_language))
strict digraph G {
1 [ label="ServerA" ];
2 [ label="[Server] [name:server-a]" ];
3 [ label="ServerB" ];
4 [ label="[Server] [name:server-b]" ];
5 [ label="iis" ];
6 [ label="[IIS] undefined" ];
7 [ label="Kubernetes" ];
8 [ label="[Kubernetes] undefined" ];
9 [ label="appA" ];
10 [ label="appB" ];
11 [ label="files" ];
12 [ label="[Files] undefined" ];
13 [ label="maven" ];
14 [ label="[Maven] undefined" ];
15 [ label="my-app-1" ];
16 [ label="my-app-2" ];
17 [ label="[Artifact] com.mycompany.app:my-app-1" ];
18 [ label="[Artifact] com.mycompany.app:my-app-2" ];
2 -> 1;
4 -> 3;
5 -> 2;
6 -> 5;
7 -> 2;
8 -> 7;
9 -> 8;
10 -> 6;
12 -> 11;
13 -> 12;
14 -> 13;
15 -> 14;
16 -> 14;
17 -> 15;
18 -> 16;
16 -> 17;
}
Using a visual DOT renderer, we get this image represention of the dot output :
Upon an error or more precisely when a statement is not matched, you'll see a report of the remaining INV's statements.
Here is an example:
[INV] ---- [DIGEST] started ----
[INV] ---- [DIGEST] #1 (state=RUNNING) ----
[INV] [my-server] => [BROADCAST] [Server] my-server-id
my-server-id has been broadcast
[INV] ---- [DIGEST] #2 (state=RUNNING) ----
[INV] [my-webservice] => [REQUIRE] [Server] my-server-id
[INV] [my-webservice] => [BROADCAST] [Endpoint] my-webservice-id
my-webservice-id has been broadcast
[INV] ---- [DIGEST] #3 (state=RUNNING) ----
[INV] nothing done
[INV] ---- [DIGEST] #4 (state=UNBLOATING) ----
[INV] nothing unbloated
[DEBUG] executor is shutting down
[INV] Completed INV(s): 2
[INV] Incompleted INV(s): 3
[WARN] INV(s):
- my-app has 2 statement(s) left:
1 requirement(s):
[NOT MATCHED] [my-app] => [REQUIRE] [Endpoint] my-webservice-id-not-existing
1 broadcast(s):
[REQUIRED BY 2] [my-app] => [BROADCAST] [App] my-app-id
- my-app-2 has 4 statement(s) left:
3 requirement(s):
[NOT MATCHED] [my-app-2] => [REQUIRE] [Endpoint] my-webservice-id-not-existing
[COULD MATCH] [my-app-2] => [REQUIRE] [App] my-app-id
[UNBLOATABLE] [my-app-2] => [REQUIRE] [Endpoint] my-unbloatable-endpoint
1 broadcast(s):
[REQUIRED BY 1] [my-app-2] => [BROADCAST] [App] my-app-id-2
- my-app-3 has 5 statement(s) left:
4 requirement(s):
[NOT MATCHED] [my-app-3] => [REQUIRE] [Endpoint] my-webservice-id-not-existing
[COULD MATCH] [my-app-3] => [REQUIRE] [App] my-app-id
[COULD MATCH] [my-app-3] => [REQUIRE] [App] my-app-id-2
[WOULD MATCH] [my-app-3] => [REQUIRE] [Endpoint] my-webservice-id
1 broadcast(s):
[REQUIRED BY 0] [my-app-3] => [BROADCAST] [App] my-app-id-3
[INV] ---- [DIGEST] completed ----
- REQUIRED BY #: Shows how many require statements would have consumed this broadcast statement
- NOT MATCHED: A require statement that CAN'T be matched with the remaining INV's as it is when reported.
- WOULD MATCH: A require statement matching an available broadcast statement. The later was made available during a RUNNING or UNBLOATING cycle
- COULD MATCH: A require statement matching a non-available broadcast statement. The later was found in the remaining INV's broadcast statements during this reporting.
- UNBLOATABLE: A require statement that would have unbloatable