blob: 1ecb1b78f7b66e7de8489e06d1bd656af36797cb [file] [log] [blame]
Hector Anapan72db1212017-10-18 11:02:24 -04001.. ============LICENSE_START==========================================
2.. ===================================================================
3.. Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4.. ===================================================================
5.. Licensed under the Creative Commons License, Attribution 4.0 Intl. (the "License");
6.. you may not use this documentation except in compliance with the License.
7.. You may obtain a copy of the License at
8..
9.. https://creativecommons.org/licenses/by/4.0/
10..
11.. Unless required by applicable law or agreed to in writing, software
12.. distributed under the License is distributed on an "AS IS" BASIS,
13.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14.. See the License for the specific language governing permissions and
15.. limitations under the License.
16.. ============LICENSE_END============================================
17.. ECOMP is a trademark and service mark of AT&T Intellectual Property.
18
Hector Anapanfd135332017-10-18 20:50:05 -040019====================
20APPC Ansible Adapter
21====================
Hector Anapan33a21fd2017-09-30 01:55:20 -040022
23This wiki provides documentation regarding the design, capabilities and
24usage of the Ansible Extension for APP-C. Ansible_ is a an open-source
25VNF management framework that allows provide an almost cli like set of
26tools in a structured form. It is agentless in that the target VNF need
27not have any additional software other than:
28
29a) SSH server
30b) Python >= 2.7
31c) Any necessary software that is specific to the VNF to run its functions.
32
33Any action (e.g configure, restart, health check etc) can be
34executed on the VNF by constructing a **playbook (or set of playbooks)**
35that is executed by an Ansible agent on the VNF via SSH.
36
37The Ansible Extension for APP-C allows management of VNFs that support Ansible
38through the following three additions :
39
40 - **An APP-C/Ansible Server interface:** Ansible libraries are written in python and hence cannot be executed natively from within the APP-C Karaf container. Instead, the design calls for an **Ansible Server** that can execute the Ansible playbooks and exposes a **REST** interface that is compliant with requirements of APP-C. These requirements are documented as the Server API Interface that any compliant Ansible Server must support. Exact implementation of the Ansible Server is left open and does not affect APP-C operations as long as the server follows the interface. For purposes of evaluation, a reference web server that implements this APP-C/Ansible Server interface has been developed and the code is available from the App-C ONAP repository under *appc-adapters/appc-ansible-adapter/appc-ansible-example-server*.
41
42 - **An APP-C Ansible adapter:** The ansible adapter is an OSGI bundle in the APP-C Karaf container that interacts with the Ansible Server . It is essentially a set of REST calls that performs two actions, submit request for a playbook to be executed, and if required get the results of the playbook after execution (if in synchronous mode).
43
44 - **Ansible Directed Graph (DG):** The Ansible Directed graph is generic DG that can be used to invoke any playbook via Ansible (and hence any APP-C action, since in Ansible, VNF actions map to playbooks) corresponding to an LCM action.
45
46The architecture design for supporting Ansible is outlined in the diagram below :
47
48|image0|
49
50The workflow envisioned when Application Controller receives an event is
51as follows :
52
531) Application Controller receives event from the Event Bus for an LCM action.
542) The appropriate LCM API invokes the Dispatcher which performs the relevant lookups for A&AI and Workflow (DG information).
553) The dispatcher calls the DG relevant to the LCM action (for the VNF).
564) The DG conducts any processing of data (e.g retrieving additional information, filling templates etc) , prepares the necessary DG context variables outlined in Table 1 and then invokes the Ansible DG.
575) Ansible DG leverages the Ansible Adapter to interact with the Ansible Server.
586) Ansible Server invokes the appropriate playbook which in turn interacts with the VNF and then returns the playbook results.
597) Ansible Server returns results.
608) Ansible DG provides these results back to calling DG.
61
62A ladder diagram of the work flow is pasted below :
63
64|image1|
65
66Details of each of these three (DG, Adapter and Ansible Server) are listed below :
67
681. **Ansible Directed Graph (DG):** The Ansible Directed graph is the most common way an App-C developer is expected to leverage Ansible functionality. The Ansible DG is a general purpose graph that can be used to invoke and retrieve results from any playbook on an ONAP-compliant Ansible Server. The Ansible Graph,when called, expects a certain set of inputs to be provided as input and when upon completion provides results from the execution of the Ansible playbook. The Ansible
69DG can be invoked using the following (current) naming:
70
71+------------+----------------------+
72| Field | Value |
73+============+======================+
74| module | APPC |
75+------------+----------------------+
76| rpc | ansible-adapter-1.0 |
77+------------+----------------------+
78| version | 2.0.1 |
79+------------+----------------------+
80
81The inputs that the Ansible DG expects in DG context memory are listed below:
82
83Table 1: Input Parameters to the Ansible Directed Graph
84
85+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
86| Variable Name | Description | Type | Comments |
87+================+=================================================================+=======================+==========================================================================+
88| User | Username to logon to Ansible Server | Mandatory | Should be provided by APPC. |
89+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
90| Password | Password to logon to Ansible Server | Mandatory | Should be provided by APPC. |
91+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
92| AgentUrl | The complete URL of the Ansible Server to post the request for | Mandatory | Should be provided by APPC. |
93| | execution and retrieve results (if in synchronous mode) | | |
94+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
95| PlaybookName | Name/identifier of playbook to run | Mandatory | To be provided in the template. |
96+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
97| Action | The type of VNF action being requested | Optional | Provided either by APPC or Template. |
98+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
99| EnvParameters | A JSON dictionary (stringified) listing the parameters to be | Optional | Structure of the EnvParameters dictionary to be supplied in template. |
100| | passed to the Ansible playbook | | Values to be filled in by App-C based on values from payload in run-time |
101+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
102| FileParameters | A JSON dictionary (stringified) listing file names and files to | Optional | Structure of the FileParameters dictionary to be supplied in template. |
103| | be created for Ansible playbook | | Values to be filled in by App-C based on values from payload in run-time |
104+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
105| Timeout | Time Ansible Server should wait before terminating playbook | Optional | To be provided in the template. |
106+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
107| NodeList | List of FQDNs/IP Addresses of VNF that the Ansible playbook | Optional | To be provided to App-C during Runtime. |
108| | should be executed on. | (if not supplied, | |
109| | | will run on server) | |
110+----------------+-----------------------------------------------------------------+-----------------------+--------------------------------------------------------------------------+
111
112 The 'template' referred in the above table must be a JSON file as documented in the VNF vendor requirements and must contain the key-value pairs listed above (that are expected to be in the template). An LCM API Directed graph should fill in necessary parameters in the template, and then put the key-value pairs from the template as listed above in DG context memory before calling the Ansible DG.
113
114Upon completion the Ansible DG sets the following variables in DG context memory
115
116Table 2: Output Variables set by Ansible DG Variable
117
118+-----------------------+--------------------------------------------------------------------------+
119| Type | Comments |
120+=======================+==========================================================================+
121| output.status.code | Result of the request: 400 if SUCCESS , 200 if FAILURE. |
122| | |
123| | The ansible playbook may have multiple sub-tasks, playbooks etc and may |
124| | run on multiple VMs of a host. The request is considered to fail if even |
125| | one of the tasks is incomplete. |
126+-----------------------+--------------------------------------------------------------------------+
127| output.status.message | If playbook finished, set to FINISH, if playbook terminated, set to |
128| | TERMINATED. If abnormal error, reported in message |
129+-----------------------+--------------------------------------------------------------------------+
130| output.status.results | A JSON dictionary with results corresponding to output provided by the |
131| | Ansible playbook request. This is optional (may not be present if |
132| | playbook was terminated). The results, if present, will be in the form |
133| | of a dictionary that follows the format presented in the Ansible Server |
134| | API Documentation. The document also contains examples of output. |
135+-----------------------+--------------------------------------------------------------------------+
136
137 *Note : The Ansible Server supports a Callback Url functionality, but it is currently not invoked by App-C Ansible Adapter or Directed Graph. If added, it is easy to change the Adapter and Ansible DG to support this.*
138
1392. **APP-C Ansible Adapter:** The App-C Ansible Adapter is an OSGI bundle which essentially makes REST calls to the Ansible Server. It exposes three methods that can be invoked by the Service Logic Interpreter (SLI).
140
141 a. *void reqExec(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException*: A method to invoke the test.
142
143 b. *void reqExecResult(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException*: A method to request results of a test.
144
145 c. *void reqExecLog(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException* : A method to retreive the logs from a request (not used in the Ansible DG currently).
146
147 Currently, the Ansible DG uses only the first two (reqExec and reqExecResult) since only these two are needed to request execution of a playbook and retrieval of results. The reqExecLog is for diagnostic purposes.
148
149 In order to communicate with the Ansible Server, it is currently assumed that:
150
151 a. Credentials comprise of a username and password.
152
153 b. Communication is over https
154
155 The Ansible Adapter has three configurable parameters related to SSL certificate of the Ansible Server, which can be set from the properties file:
156
Patrick Brady2ad82142017-12-13 12:49:38 -0800157 a. org.onap.appc.adapter.ansible.clientType. If set to "TRUST\_ALL", will accept all SSL certificates from any Ansible Server. If set to "TRUST\_CERT", will accept SSL from only those Ansible Servers whose certificate is in the trustStore keystore file. These two options can be used for development environment. Default option is to trust only well known server certificates (use in Production).
Hector Anapan33a21fd2017-09-30 01:55:20 -0400158
Patrick Brady2ad82142017-12-13 12:49:38 -0800159 b. org.onap.appc.adapter.ansible.trustStore used to point to the keystore file
Hector Anapan33a21fd2017-09-30 01:55:20 -0400160
Patrick Brady2ad82142017-12-13 12:49:38 -0800161 c. org.onap.appc.adapter.ansible.trustStorePasswd used to set password for keystore file
Hector Anapan33a21fd2017-09-30 01:55:20 -0400162
1633. **Reference Ansible Server Implementation of APPC / Ansible Interface (for testing purposes only)**
164
165 a. Overview
166
167 |image2|
168
169 b. Inventory file
170
171 The Prototype Ansible Server requires that all credentials and IP Addresses for the VNF being tested either already be present in the Servers Database or be loaded before any playbooks are invoked. Supported credentials are user-name/password and public-key authentication.
172
173 All VNF credentials stored in a unique file (or in a SQL database depending on the ansible server runtime configuration):
174
Hector Anapan8ecf0e42017-10-18 12:10:55 -0400175 .. code:: bash
Hector Anapan33a21fd2017-09-30 01:55:20 -0400176
Hector Anapan8ecf0e42017-10-18 12:10:55 -0400177 [host]
178 localhost ansible\_connection=local
179 ...
180 [hostgroup1]
181 hostname11 ansible\_connection=ssh ansible\_ssh\_user=loginid11 ansible\_ssh\_pass=passwd11
182 hostname12 ansible\_connection=ssh ansible\_ssh\_user=loginid12 ansible\_ssh\_private\_key\_file=kefile12
183 ...
184 [hostgroup2]
185 hostname21 ansible\_connection=ssh ansible\_ssh\_user=loginid21 ansible\_ssh\_private\_key\_file=keyfile21
186 ...
187 [hostgroup3]
188 ...
Hector Anapan33a21fd2017-09-30 01:55:20 -0400189
190 c. Playbooks
191
192 Playbooks can either be provided as stand alone text files or gzipped tar file (playbooks with roles sub-directories) either stored in a local file or in an SQL database.
193
194 Naming convention: anything\_LCM@M.mn.{yml,tar.gz} where version number M is a digit and mn are subversion number digits.
195
196 Playbooks should be written such that they can run from the command line: "ansible-playbook -i inventoryfile –extra-vars optionalvariables playbookname" That means the playbook should not contain any VM credentials information, they are expected to be provided through the inventory file passed at run time.
197
198 a. Stand-alone playbooks
199
200 |image3|
201
202 b. Playbooks in gzipped tarfiles
203
204 |image4|
205
206 d. Installation
207
208 a. Python
209
210 sudo apt-get install python2.7
211 sudo apt-get install python-pip
212 pip install PyMySQL
213 pip install requests
214
215 b. Ansible
216
217 sudo apt-get install software-properties-common
218 sudo apt-add-repository ppa:ansible/ansible
219 sudo apt-get update
220 sudo apt-get install ansible
221
222 c. SQL database
223
224 a. Installing MySQL
225
226 sudo apt-get install mysql-server
227
228 Set root passwd during installation (i.e. password\_4\_mysql\_user\_id)
229
230 sudo service mysql restart
231
232 b. Setting up mysql
233
234 mysql -u [username]-p
235
236 mysql -uroot -p
237
238 Create user (i.e. id=mysql\_user\_id psswd=password\_4\_mysql\_user\_id)
239
240 CREATE USER 'appc'@'%' IDENTIFIED BY 'password\_4\_mysql\_user\_id';
241
242 GRANT ALL PRIVILEGES ON *.* TO 'mysql\_user\_id'@'%';
243
244 SET PASSWORD FOR 'mysql\_user\_id'@'%'=PASSWORD('password\_4\_mysql\_user\_id');
245
246 c. Creating schema
247
248 CREATE SCHEMA ansible;
249
250 SHOW DATABASES;
251
252 USE ansible;
253
254 CREATE TABLE playbook (name VARCHAR(45) NOT NULL, value BLOB, type VARCHAR(60), version VARCHAR(60), PRIMARY KEY (name));
255
256 SHOW TABLES;
257
258 CREATE TABLE inventory (hostname VARCHAR(45) NOT NULL, hostgroup VARCHAR(45), credentials VARCHAR(500), PRIMARY KEY (hostname));
259
260 SHOW COLUMNS FROM playbook;
261
262 SHOW COLUMNS FROM inventory;
263
264 GRANT ALL PRIVILEGES ON *.* TO 'mysql\_user\_id'@'%' IDENTIFIED BY 'password\_4\_mysql\_user\_id' WITH GRANT OPTION;
265
266 GRANT ALL PRIVILEGES ON *.* TO 'ansible'@'%' IDENTIFIED BY 'ansible\_agent' WITH GRANT OPTION;
267
268 FLUSH PRIVILEGES;
269
270
271
272 d. Loading playbooks and inventory data in SQL database
273
274 Place inventory file and playbooks to be loaded in one directory, set LoadAnsibleMySql variables:
275
276 SQL credentials:
277
278 host="localhost" # your host, usually localhost
279 user="mysql\_user\_id" # your username
280 passwd="password\_4\_mysql\_user\_id" # your password
281 db="ansible" # name of the database
282
283
284 Path of playbook location:
285
286 playbook\_path = "something/something/"
287
288
289 Full name of inventory file:
290
291 inventory = "something/something/Ansible\_inventory"
292
293 These variables are located right after main:
294
295 |image5|
296
297 Run loader: python LoadAnsibleMySql.py
298
299 e. Execution
300
301 Ansible server is executed through RestServer.py. Its configuration file consists of the following:
302
Hector Anapan8ecf0e42017-10-18 12:10:55 -0400303 .. code:: bash
304
305 # Host definition
306 ip: 0.0.0.0
307 port: 8000
308
309 # Security (controls use of TLS encrypton and RestServer authentication)
310 tls: no
311 auth: no
312
313 # TLS certificates (must be built on application host)
314 priv: provide\_privated\_key.pem
315 pub: provide\_public\_key.pem
316
317 # RestServer authentication
318 id: provide\_RestServer\_id
319 psswd: provide\_password\_4\_RestServer\_id
320
321 # Mysql
322 host: localhost
323 user: mysql\_user\_id
324 passwd: password\_4\_mysql\_user\_id
325 db: ansible
326
327 #Playbooks
328 from\_files: yes
329 ansible\_path: /home/ubuntu/RestServerOpenSource
330 ansible\_inv: Ansible\_inventory
331 ansible\_temp: PlaybooksTemp
332 timeout\_seconds: 60
333
334 # Blocking on GetResults
335 getresults\_block: yes
Hector Anapan33a21fd2017-09-30 01:55:20 -0400336
337Execution and testing steps:
338
339 1. **Start RestServer**: *python RestServer.py*
340
341 Note: RSA key fingerprint needs to be loaded manually in server for each VM defined in inventory file that requires ssh authentication. This can be done by testing ssh credentials to each target VM and accepting RSA key fingerprint:
342
343 .. code:: bash
344
345 ssh -i key \|VMaddress\|
346 RSA key fingerprint is \|something.\|
347 Are you sure you want to continue connecting (yes/no)? yes
348
349
350 2. **Try curl commands** (case no secured REST: HTTP & no authentication)
351
352 Request to execute playbook:
353
354 .. code:: bash
355
356 curl -H "Content-type: application/json" -X POST -d '{"Id": "10", "PlaybookName": "ansible\_sleep", "NodeList": ["host"], "Timeout": "60", "EnvParameters": {"Sleep": "10"}}'http://0.0.0.0:8000/Dispatch
357
358 Response:
359
360 .. code:: bash
361
362 {"ExpectedDuration": "60sec", "StatusMessage": "PENDING", "StatusCode": 100}
363
364 Get results (blocked until test finished):
365
366 .. code:: bash
367
368 curl -H "Content-type: application/json" -X GET "http://0.0.0.0:8000/Dispatch/?Id=10&Type=GetResult"
369
370 Response:
371
372 .. code:: bash
373
374 {"Results": {"localhost": {"GroupName": "host", "StatusMessage": "SUCCESS", "StatusCode": 200}}, "PlaybookName":"ansible\_sleep", "Version": "0.00", "Duration": "11.261794", "StatusMessage": "FINISHED", "StatusCode": 200}
375
376 Delete playbook execution information
377
378 .. code:: bash
379
380 curl -H "Content-type: application/json" -X DELETE http://0.0.0.0:8000/Dispatch/?Id=10
381
382 Response:
383
384 .. code:: bash
385
386 {"StatusMessage": "PLAYBOOK EXECUTION RECORDS DELETED", "StatusCode": 200}
387
388Playbook execution done through system call
389
390 .. code:: bash
391
392 ansible-playbook --v -extra-vars playbookvars -i inventoryfile playbook.yml
393
394 - Inventory file created at run time, playbook loaded from mysql, both placed in the temporary directory destroyed at end of test (Playbook archive is unpacked in the temporary directory)
395
396All tested playbooks written such that the ansible play recap log indicates whether or not the playbook tasks succeeded (multiple tasks in a standalone playbook or playbooks with roles directory structure)
397
398Sample ansible play recap’:
399
400|image6|
401
402
403
404.. _Ansible: https://www.ansible.com/
405
406.. |image0| image:: images/image0.png
407.. |image1| image:: images/image1.png
408.. |image2| image:: images/image2.png
409.. |image3| image:: images/image3.png
410.. |image4| image:: images/image4.png
411.. |image5| image:: images/image5.png
412.. |image6| image:: images/image6.png