ligoj-cli 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,2350 @@
1
+ Metadata-Version: 2.4
2
+ Name: ligoj-cli
3
+ Version: 1.0.0
4
+ Summary: Ligoj CLI
5
+ Author-email: Fabrice Daugan <fdaugan@kloudy.io>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ligoj/cli
8
+ Project-URL: Documentation, https://github.com/ligoj/cli/README.md
9
+ Project-URL: Repository, https://github.com/ligoj/cli
10
+ Project-URL: Issues, https://github.com/ligoj/cli/issues
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Operating System :: OS Independent
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: colorama==0.4.6
21
+ Requires-Dist: requests==2.32.4
22
+ Requires-Dist: dnspython==2.7.0
23
+ Requires-Dist: pyyaml==6.0.2
24
+ Requires-Dist: configparser==7.2.0
25
+ Requires-Dist: unidecode==1.4.0
26
+ Requires-Dist: jsonschema===4.25.0
27
+ Requires-Dist: jsonmerge==1.9.2
28
+ Requires-Dist: Jinja2==3.1.6
29
+ Requires-Dist: pytimeparse==1.1.8
30
+ Dynamic: license-file
31
+
32
+ [[_TOC_]]
33
+
34
+ # Description
35
+
36
+ Ligoj CLI makes REST calls to a remote Ligoj instance, with parameters and error handling.
37
+
38
+ # Requirements
39
+
40
+ - Python 3.11+
41
+ - Connectivity and API keys to target endpoints `Ligoj`, `Nexus`, `Jenkins`, `SonarQube`
42
+ - `pip`
43
+ - Valid [credentials](#credentials)
44
+
45
+
46
+ # Configuration
47
+
48
+ ## Credentials
49
+
50
+ Ligoj credentials are based on user/password or user/API Key.
51
+
52
+ Populate the [configuration files](#configuration-files) with the API key created here [#/api/token ("?" > "Api" > "Token")](http://localhost:8080/ligoj/#/api/token)
53
+
54
+ You can also:
55
+ - use the [session login](#login-with-password) command to get a temporary session
56
+ - use the [token](#token) command to create durable API keys
57
+
58
+ For standard actions, only `LIGOJ_ENDPOINT` is required and can be set either in the [configuration files](#configuration-files), as an environment variable, or as a CLI option.
59
+
60
+ For `bootstrap` actions, more endpoints and credentials may be required in the [configuration files](#configuration-files).
61
+
62
+ Sample usage:
63
+
64
+ ```bash
65
+ ligoj \
66
+ --api-user="ligoj-admin" \
67
+ --api-key="..." \
68
+ --endpoint="http://localhost:8080/ligoj" \
69
+ --version
70
+ ```
71
+
72
+ # Commands
73
+
74
+ ## Settings
75
+
76
+ Options are sourced in the following order of priority, from highest to lowest:
77
+
78
+ 1. Command line options – Overrides settings in any other location, such as the `--output` and `--profile` parameters.
79
+ 2. Environment variables – You can store values in your system's environment variables.
80
+ 3. Session file – `default` section or given profile name. The session file is located at `~/.ligoj/sessions` on Linux or macOS and holds:
81
+ - Session cookies set with the [`login`](#login-with-password) command.
82
+ - API keys set with the [`login`](#login-with-api-key) command.
83
+ 4. Credentials file – `default` section or given profile name. The credentials file is located at `~/.ligoj/credentials` on Linux or macOS.
84
+ 5. Configuration file – `default` section or given profile name. The config file is located at `~/.ligoj/config` on Linux or macOS. Alternative file `~/.ligoj/cli-config` is supported.
85
+
86
+
87
+ ### Configuration files
88
+
89
+ Sections in these `.ini` files correspond to profile names. The default profile name is `default` and is used when no `--profile` option and no `LIGOJ_PROFILE` are provided.
90
+
91
+ In the file `~/.ligoj/config`, default configurations can be specified. No secrets are sourced from this file.
92
+
93
+ ```ini
94
+ [default]
95
+ output = "json"
96
+ log_level = "DEBUG"
97
+ endpoint=http://localhost:8080/ligoj
98
+ jenkins_endpoint=http://localhost:8086
99
+ sonar_endpoint=http://localhost:9000/
100
+
101
+ [some]
102
+ output = "json"
103
+ ```
104
+
105
+ Read-only secrets are stored in the `~/.ligoj/credentials` file.
106
+
107
+ Temporary secrets (stored from the [`session`](#session) command) are stored in the `~/.ligoj/sessions` file.
108
+
109
+ While `~/.ligoj/credentials` can contain configuration settings, secrets are only sourced from the `~/.ligoj/credentials` and `~/.ligoj/sessions` files.
110
+
111
+ Sample credential file:
112
+ ```ini
113
+ [default]
114
+ api_user = ligoj-user1
115
+ api_key = secret
116
+ jenkins_api_user = admin
117
+ jenkins_api_token = secret
118
+ sonar_api_token = secret
119
+ ```
120
+
121
+ *Note* Leading spaces are ignored, and enclosing `'` and `"` are removed. Empty strings are ignored.
122
+
123
+ ## Generic options
124
+
125
+ The generic options are available to all actions.
126
+
127
+ ### Output mode
128
+
129
+ Determines the output mode of the command. Use the `--output` option. The following modes are available:
130
+
131
+ - `json` : JSON format
132
+ - `text` : Text format
133
+
134
+ This option can also be specified in [configuration files](#configuration-files) as `output` or in environment variable `LIGOJ_OUTPUT`
135
+
136
+ ```bash
137
+ ligoj --output json --version
138
+ ligoj --version
139
+ ```
140
+
141
+ ```json
142
+ {"version": "3.3.1-SNAPSHOT"}
143
+ ```
144
+
145
+ ```bash
146
+ ligoj --output text --version
147
+ ```
148
+
149
+ ```txt
150
+ 3.3.1-SNAPSHOT
151
+ ```
152
+
153
+ ### Log level
154
+
155
+ To configure the verbosity, use the `--log-level` option. The following levels are available:
156
+
157
+ - `TRACE` level displays the in/out data. `--verbose` and `--trace` are shortcuts for this level.
158
+ - `DEBUG` level displays the internal API calls `--debug` is a shortcut for this level.
159
+ - `INFO` level displays the actions
160
+ - `WARN` level displays the unexpected behaviors
161
+ - `ERROR` level displays only fatal errors
162
+
163
+ This option can also be specified in [configuration files](#configuration-files) as `log-level` or in environment variable `LIGOJ_LOG_LEVEL`
164
+
165
+ ```bash
166
+ ligoj --log-level INFO ....
167
+ ligoj --verbose ....
168
+ ligoj --trace ....
169
+ ```
170
+
171
+ If you want to pipe JSON result to `jq`, use `--output json` and `--log-level ERROR` options.
172
+
173
+
174
+ ### Insecure server connections
175
+
176
+ To allow insecure server connections when using SSL, use the `--insecure` option. This option can also be specified in [configuration files](#configuration-files) as `insecure` or in environment variable `LIGOJ_INSECURE`
177
+
178
+ ```bash
179
+ ligoj --insecure ....
180
+ ligoj --k ....
181
+ ```
182
+
183
+ ### API user
184
+
185
+ Ligoj API user name. Use the `--api-user` option. This option can also be specified in [configuration files](#configuration-files) as `api-user` or in environment variable `LIGOJ_API_USER`. By default is `ligoj-admin`.
186
+
187
+ ```bash
188
+ ligoj --api-user ligoj-admin ....
189
+ ```
190
+
191
+ ### API key
192
+
193
+ Provide an API key, which can be created here [#/api/token ("?" > "Api" > "Token")](https://localhost:8080/ligoj/#/api/token). Use the `--api-key` option. This option can also be specified in [configuration files](#configuration-files) as `api-key` or in environment variable `LIGOJ_API_KEY`
194
+
195
+ ```bash
196
+ ligoj --api-key secret ....
197
+ ```
198
+
199
+
200
+ ### API run as user
201
+
202
+ Ligoj API user name for impersonation. Use the `--api-run-as-user` option. This option can also be specified in [configuration files](#configuration-files) as `api-run-as-user` or in environment variable `LIGOJ_API_RUN_AS_USER`.
203
+
204
+ Constraints are:
205
+ - After the authentication succeeds with [--api-key](#api-key) and [--api-user](#api-user)
206
+ - The current user must have `POST /system.user` authorization
207
+ - `--api-run-as-user` must exist
208
+ - The actions are executed in the name of `--api-run-as-user` and without needing the related credentials.
209
+
210
+ This option can also be specified in [configuration files](#configuration-files) as `api-run-as-user` or in environment variable `LIGOJ_API_RUN_AS_USER`.
211
+
212
+ ```bash
213
+ ligoj --api-run-as-user ligoj-user ....
214
+ ```
215
+
216
+
217
+ ### API local roles
218
+
219
+ Restrict the computed roles to the local roles of the authenticated user. No plugin roles are involved.
220
+ This flag makes the authentication independent of the configured plugins (e.g., availability, misconfiguration, etc.).
221
+
222
+ Since this flag reduces the set of available roles, there is no restriction on the usage.
223
+
224
+ This option can also be specified in [configuration files](#configuration-files) as `api-local-roles` or in environment variable `LIGOJ_API_LOCAL_ROLES`.
225
+
226
+ ```bash
227
+ ligoj --api-local-roles session get
228
+ ```
229
+
230
+
231
+ ### Profile
232
+
233
+ Ligoj profile name to read from [configuration files](#configuration-files), `credentials`, `config`, and `sessions`. Use the `--profile` option. This option can also be specified with environment variable `LIGOJ_PROFILE`. The default is `default`.
234
+
235
+ ```bash
236
+ ligoj --profile some ....
237
+ ```
238
+
239
+ ### From
240
+
241
+ JSON content to load. Use the `--from` option. The following forms are available:
242
+
243
+ - Path to a local JSON file
244
+ - Remote HTTP URL
245
+ - Inline JSON string
246
+
247
+ After the content has been retrieved, it is interpolated with [Jinja](https://pypi.org/project/Jinja2/) with current project (`project`) and environment variables (`env`) as context:
248
+ - For example:
249
+ - `{{ project.id }}` is replaced by the project identifier.
250
+ - `{{ env.ENV_VAR }}` is replaced by the `ENV_VAR` environment variable value.
251
+ - `$${_not_existing_property_in_context_}` is replaced by an empty string.
252
+ - `null` values are considered as empty string
253
+ - The context depends on the current action. Usually, all given parameters are added to the context.
254
+ - The context is completed with environment variables.
255
+ - Surrounding spaces inside `{{..}}` are ignored
256
+
257
+ ### No color
258
+
259
+ Disable colors in messages. Use the `--no-color` option. This option can also be specified in [configuration files](#configuration-files) as `no-color` or in environment variable `LIGOJ_NO_COLOR`
260
+
261
+ ```bash
262
+ ligoj --no-color ....
263
+ ```
264
+
265
+ ### Fail on hook error
266
+
267
+ Fail (exit code 1) when any hook returns a failure status (`X-Ligoj-Hook-*=FAILED`). See [hooks](https://github.com/ligoj/ligoj/blob/master/DOC.md#hook) for more details. Use the `--fail-on-hook-error` option. This option can also be specified in [configuration files](#configuration-files) as `fail-on-hook-error` or in environment variable `LIGOJ_FAIL_ON_HOOK_ERROR`
268
+
269
+ ```bash
270
+ ligoj --fail-on-hook-error ....
271
+ ```
272
+
273
+ Fail (exit code 1) when any hook returns a failure status (`X-Ligoj-Hook-*=FAILED`). See [hooks](https://github.com/ligoj/ligoj/blob/master/DOC.md#hook) for more details.
274
+
275
+ Hooks status and message are displayed with `DEBUG` log level:
276
+ ```log
277
+ [DEBUG] [ligoj] Hook 'audit_role_change' status: SUCCEED
278
+ [DEBUG] [ligoj] Hook 'audit_role_change' status: FAILED: Message for user
279
+ ```
280
+
281
+ ## Session
282
+
283
+ Session operations with credentials and profile management.
284
+
285
+ ### Login with password
286
+
287
+ Verify the provided user and password and save the returned session cookie into the `~/.ligoj/sessions` file for further API call without providing credentials.
288
+
289
+ *Note* Secrets like `api-user` and `password` are sourced from the CLI options, sessions and credential files, not from the configuration one.
290
+
291
+
292
+ ```bash
293
+ ligoj --api-user "ligoj-admin" --profile default session login --password secret
294
+ ligoj --api-user "ligoj-admin" login session --password secret
295
+ ```
296
+
297
+ Completed `~/.ligoj/sessions` file:
298
+
299
+ ```ini
300
+ [default]
301
+ session = session_secret_value.node0
302
+ api_user = ligoj-admin
303
+ ```
304
+
305
+ ### Login with api key
306
+
307
+ Verify the provided user and API key and save the provided API user and API keys into the `~/.ligoj/sessions` file for further API call without providing credentials.
308
+
309
+ *Note* Secrets like `api-user` and `password` are sourced from the CLI options, sessions and credential files, not from the configuration one.
310
+
311
+ ```bash
312
+ ligoj --api-user "ligoj-admin" --api-key "__api_key__" session login
313
+ ```
314
+
315
+ ### Get session
316
+
317
+ Return user session details
318
+
319
+ ```bash
320
+ ligoj session get
321
+ ```
322
+
323
+ ```json
324
+ {
325
+ "applicationSettings": {
326
+ "buildNumber": "", "buildTimestamp": "", "buildVersion": "3.3.1-SNAPSHOT",
327
+ "digestVersion": "rRXmeWPgn+...==",
328
+ "plugins": ["feature:welcome:data-rbac"]
329
+ },
330
+ "userSettings": {"restricted-hash--": "#/home/project/1/subscription/1002", "security-agreement": "1"},
331
+ "uiAuthorizations": ["^id/container/group.*", "^id/user.*", "^id/delegate.*", "^message.*", "^id$", "^home.*", "^id/container/company.*", "^api.*", "^id/home.*", ".*"],
332
+ "apiAuthorizations": [{"pattern": ".*", "method": "DELETE"}], "roles": ["ADMIN", "USER"], "userName": "ligoj-admin"
333
+ }
334
+ ```
335
+
336
+ ### whoami
337
+
338
+ Return user identifier
339
+
340
+ ```bash
341
+ ligoj session whoami
342
+ ```
343
+
344
+ ```json
345
+ {"id": "ligoj-admin"}
346
+ ```
347
+
348
+
349
+ ## System User
350
+
351
+ A system user can live without federated identity. After a successful login, a federated user can be managed with system roles and API keys.
352
+
353
+
354
+ ### Create a system user
355
+
356
+ Create a new system user with role names or identifiers.
357
+
358
+ ```bash
359
+ ligoj user upsert --id ligoj-admin@sample.com --roles USER ADMIN
360
+ ```
361
+
362
+ Optionally, at this time, an API key is generated but only once and only from administrator users.
363
+
364
+ ```bash
365
+ ligoj user upsert --id ligoj-admin@sample.com --roles USER ADMIN --api_key_name cli
366
+ ```
367
+
368
+ Output the API key only if not existing.
369
+
370
+ ```json
371
+ {"id": "__api_key__", "name": "cli"}
372
+ ```
373
+
374
+ *Note* When role names are provided API calls are executed to retrieve their identifiers.
375
+
376
+ ### Delete a system user
377
+
378
+ Delete a system user. The command will not fail if the user is not found.
379
+
380
+ ```bash
381
+ ligoj user delete --id ligoj-user
382
+ ```
383
+
384
+
385
+ ### List system users
386
+
387
+ ```bash
388
+ ligoj user list
389
+ ligoj user list --with-roles
390
+ ```
391
+
392
+ ```json
393
+ {"recordsTotal": 3, "recordsFiltered": 3, "data": ["ligoj-admin", "ligoj-admin@sample.com", "ligoj-user"]}
394
+ ```
395
+
396
+ *Note* When role names are provided API calls are executed to retrieve their identifiers.
397
+
398
+
399
+ ### Delete a system user
400
+
401
+ Create a new system user with role names or identifiers.
402
+
403
+ ```bash
404
+ ligoj user delete --id ligoj-user
405
+ ```
406
+
407
+
408
+ ## System Role
409
+
410
+ A system role holds the permissions (ui and api), and can be assigned to users or groups.
411
+
412
+
413
+ ### Create a system role
414
+
415
+ Create or update a system role.
416
+
417
+ **Note** Whereas Ligoj supports per HTTP method authorizations, this feature is not yet available from this CLI action.
418
+
419
+ ```bash
420
+ # Deprecated `--id` option
421
+ ligoj role create --id ADMIN --api ".*" --ui ".*"
422
+ ligoj role create --name ADMIN --api ".*" --ui ".*"
423
+ ligoj role create --name SELF_TOKEN_RENEW --api "/api/token.*" --ui "/sys/token"
424
+ ```
425
+
426
+ Output is the created/existing role identifier.
427
+ ```json
428
+ 123
429
+ ```
430
+
431
+ ### Delete a system role
432
+
433
+ Delete a system role. The command will not fail if the role does not exist.
434
+
435
+ ```bash
436
+ ligoj role delete --id 1
437
+ ligoj role delete --name ADMIN
438
+ ```
439
+
440
+ ### List system roles
441
+
442
+ ```bash
443
+ ligoj role list
444
+ ```
445
+
446
+ ### Get a system role
447
+
448
+ ```bash
449
+ ligoj role get --id 1
450
+ ligoj role get --name ADMIN
451
+ ```
452
+
453
+ ```json
454
+ {"id": 1, "createdBy": "_system", "createdDate": 1758279349911, "lastModifiedBy": "_system", "lastModifiedDate": 1758279349911, "name": "ADMIN"}
455
+ ```
456
+
457
+ ## Info
458
+
459
+ ### Status
460
+
461
+ Return API server status
462
+
463
+ ```bash
464
+ ligoj info status
465
+ ```
466
+
467
+ ```json
468
+ {"status": "UP"}
469
+ ```
470
+
471
+ Optionally, a wait for status can be defined. A regular poll to the server [status](#status) is performed until reaching `DOWN` or `UP` status.
472
+ When different from `0`, the final status is returned.
473
+
474
+ ```bash
475
+ ligoj info status --wait 20
476
+ ```
477
+
478
+ ```json
479
+ {"status": "DOWN"}
480
+ ```
481
+
482
+ ### Version
483
+
484
+ Return API server version
485
+
486
+ ```bash
487
+ ligoj info version
488
+ ligoj --version
489
+ ligoj -v
490
+ ```
491
+
492
+ ```json
493
+ {"version": "3.3.1-SNAPSHOT"}
494
+ ```
495
+
496
+
497
+ ### API Specification
498
+
499
+ All Ligoj APIs are accessible with REST verbs.
500
+
501
+ Currently 3 specification formats are available:
502
+ - Swagger : Web UI based on OpenAPI JSON file
503
+ - OpenAPI JSON file
504
+ - [WADL](https://www.w3.org/submissions/wadl/)
505
+
506
+ ```bash
507
+ ligoj info api --output openapi --print content
508
+ ligoj info api
509
+ ```
510
+
511
+ ```json
512
+ {
513
+ "openapi" : "3.0.1",
514
+ "info" : {
515
+ "title" : "Ligoj API application",
516
+ "description" : "REST API services of application. Includes the core services and the features of actually loaded plugins",
517
+ "contact" : {
518
+ "name" : "The Ligoj team",
519
+ "url" : "https://github.com/ligoj"
520
+ ```
521
+
522
+ ```bash
523
+ ligoj info api --output wadl --print url
524
+ ligoj info api --output openapi --print url
525
+ ligoj info api --output swagger --print url
526
+ ```
527
+
528
+ ```text
529
+ http://localhost:8080/ligoj/rest?_wadl
530
+ http://localhost:8080/ligoj/rest/openapi.json
531
+ http://localhost:8080/ligoj/api-docs?url=openapi.json
532
+ ```
533
+
534
+ ## Token
535
+
536
+ Manage API keys of current user.
537
+
538
+ ### Create a token
539
+
540
+ For `expiration` option:
541
+ - Either a full ISO date, which corresponds to the furthest date the generated token can be trusted.
542
+ - Either a duration starting from now, in a standard duration format. See [pytimeparse](https://pypi.org/project/pytimeparse/)
543
+
544
+ Expired tokens are neither listed nor returned even if they are not yet physically deleted.
545
+
546
+ ```bash
547
+ ligoj token create --id cli_init
548
+ ligoj token create --id today_only --expiration 1d
549
+ ligoj token create --id SELF_TOKEN_RENEW --expiration 2029-12-31T23:59:59
550
+ ```
551
+
552
+ Optionally, the created token can be saved into the current profile, replacing any previously existing one:
553
+
554
+ Output:
555
+
556
+ ```json
557
+ {"id": "__api_key__", "name": "cli_init"}
558
+ ```
559
+
560
+ ### List tokens
561
+
562
+ ```bash
563
+ ligoj token list
564
+
565
+ ["cli_init", "test"]
566
+ ```
567
+
568
+ ### Get a token value
569
+
570
+ ```bash
571
+ ligoj token get --id cli_init
572
+
573
+ ```json
574
+ {"value": "__api_key__"}
575
+ ```
576
+
577
+ ### Delete a token value
578
+
579
+ ```bash
580
+ ligoj token delete --id cli_init
581
+ ```
582
+
583
+ ### Version
584
+
585
+ Return API server version
586
+
587
+ ```bash
588
+ ligoj info version
589
+ ligoj --version
590
+ ligoj -v
591
+ ```
592
+
593
+ ```json
594
+ {"version": "3.3.1-SNAPSHOT"}
595
+ ```
596
+
597
+
598
+ ## Configuration
599
+
600
+ Configure global values
601
+
602
+ ### Set value
603
+
604
+ ```bash
605
+ ligoj configuration set --id "foo" --value "bar"
606
+ ligoj configuration set --id "plugins.repository-manager.nexus.search.url" --value "https://localhost/?g:org.ligoj.plugin"
607
+ ligoj configuration set --id "plugins.repository-manager.nexus.search.proxy.host" --value "my-proxy.local"
608
+ ligoj configuration set --id "plugins.repository-manager.nexus.search.proxy.port" --value "8080"
609
+ ligoj configuration set --id "plugins.repository-manager.nexus.artifact.url" --value "https://nexus.localhost:8443/repository/maven_corporate/org/ligoj/plugin/"
610
+ ligoj configuration set --id "cache.id-ldap-data.ttl" --value "3600"
611
+
612
+ ```
613
+
614
+
615
+ *Note* When you change a configuration related to plugin management, invalidate the related caches to retrieve the up-to-date plugin versions.
616
+
617
+ ### Get value
618
+
619
+ Return the configuration value from its `id`, which can be a Java property name or a stored value in the `S_CONFIGURATION` table.
620
+
621
+ Return a specific value. Encrypted values are returned as decrypted.
622
+
623
+ ```bash
624
+ ligoj configuration get --id "foo"
625
+ ```
626
+
627
+ ```json
628
+ {"value": "bar"}
629
+ ```
630
+
631
+ Return all values. Encrypted values are not returned.
632
+
633
+ ```bash
634
+ ligoj configuration get
635
+ ```
636
+
637
+ ```json
638
+ [{"name": "COMMAND_MODE", "value": "unix2003", "persisted": false, "secured": false, "overridden": false, "source": "systemEnvironment"},...]
639
+ ```
640
+
641
+ ### Delete value
642
+
643
+ ```bash
644
+ ligoj configuration delete --id "foo"
645
+ ```
646
+
647
+ ## Cache
648
+
649
+ ### Invalidate cache
650
+
651
+ ```bash
652
+ ligoj cache invalidate --id "node-parameters"
653
+ ligoj cache invalidate --id "nodes"
654
+ ligoj cache invalidate --id "iam-node-configuration"
655
+ ligoj cache invalidate --id "id-ldap-data"
656
+ ligoj cache invalidate --id "user-details"
657
+ ligoj cache invalidate --id "plugins-last-version-nexus"
658
+ ligoj cache invalidate
659
+ ```
660
+
661
+ ### Get cache details
662
+
663
+ ```bash
664
+ ligoj cache get --id "user-details"
665
+ ```
666
+
667
+ ```json
668
+ {
669
+ "id": "user-details",
670
+ "size": 1,
671
+ "hitCount": 123,
672
+ "missCount": 14,
673
+ "hitPercentage": 89.78102,
674
+ "missPercentage": 10.218978,
675
+ "averageGetTime": 16.860365,
676
+ "node": {"id": "00000000-0000-0000-0000-000000000000", "address": "[127.0.0.1]:5701", "version": "5.3.2", "cluster": {"id": "00000000-0000-0000-0000-000000000001", "state": "ACTIVE", "members": [{"id": "00000000-0000-0000-0000-000000000000", "address": "[127.0.0.1]:5701", "version": "5.3.2"}]}}
677
+ }
678
+ ```
679
+
680
+ ```bash
681
+ ligoj cache list
682
+ ```
683
+ ```json
684
+ [
685
+ {"id": "terraform-version", "size": 0, "hitCount": 0, "missCount": 0, "hitPercentage": 0.0, "missPercentage": 0.0, "averageGetTime": 0.0, "node": {"id": "00000000-0000-0000-0000-000000000000", "address": "[127.0.0.1]:5701", "version": "5.3.2", "cluster": {"id": "00000000-0000-0000-0000-000000000001", "state": "ACTIVE", "members": [{"id": "00000000-0000-0000-0000-000000000000", "address": "[127.0.0.1]:5701", "version": "5.3.2"}]}}},
686
+ ...
687
+ ]
688
+ ```
689
+
690
+ ## File
691
+
692
+ A [file](https://github.com/ligoj/ligoj/blob/master/DOC.md#hook) is a remote file readable and/or writable by the API container.
693
+
694
+ Related path must be authorized by the configuration value `ligoj.file.path`. This check is performed at upload and download times.
695
+
696
+ ```bash
697
+ ligoj configuration set --id "ligoj.file.path" --value "^/home/files/.*,^/home/hooks/.*,^/home/ligoj/META-INF/resources/webjars/.*,^/home/ligoj/statics/themes/.*"
698
+ ```
699
+
700
+ ### Create or update file
701
+
702
+ Upload a local file to a remote file.
703
+
704
+ ```bash
705
+ ligoj file put --from https://path/to/icon.png --path "/home/ligoj/icon.png"
706
+ ligoj file put --from docs/ui/logo.png --path "/home/ligoj/META-INF/resources/webjars/home/img/logo.png"
707
+ ligoj file put --from docs/ui/bg1.jpg --path "/home/ligoj/statics/themes/bootstrap-material-design/img/bg1.jpg"
708
+ ligoj file put --from docs/ui/logo.png --path "/home/ligoj/statics/favicon.ico"
709
+ ligoj file put --from docs/ui/logo.png --path "/home/ligoj/statics/themes/bootstrap-material-design/ico/favicon.ico"
710
+ ```
711
+
712
+ ### Delete file
713
+
714
+ ```bash
715
+ ligoj file delete --path "/home/ligoj/icon.png"
716
+ ```
717
+
718
+ ### Hook get
719
+
720
+ Download a remote file and save it to a local file.
721
+
722
+ ```bash
723
+ ligoj file get --path "/home/ligoj/icon.png" --out "./icon2.png"
724
+ ```
725
+
726
+ ## Hook
727
+
728
+ A [hook](https://github.com/ligoj/ligoj/blob/master/DOC.md#hook) is a command uploaded by a user, and triggered by a successfully invoked API call of Ligoj.
729
+
730
+ When this command is executed, it receives a `PAYLOAD` event as environment variable.
731
+
732
+ Related command must be authorized by the configuration value `ligoj.hook.path`. This check is performed at creation and execution time:
733
+
734
+ ```bash
735
+ ligoj configuration set --id "ligoj.hook.path" --value "^/home/ligoj/hooks/.*"
736
+ ligoj configuration set --id "ligoj.file.path" --value "^/home/ligoj/hooks/.*"
737
+ ligoj file put --from docs/sample_hook_ligoj_audit.sh --path "/home/ligoj/hooks/ligoj_audit.sh" --executable
738
+ ```
739
+
740
+ Payload structure:
741
+
742
+ ```json
743
+ {
744
+ "name":"audit_role_change",
745
+ "now":"2023-10-17T19:22:21Z",
746
+ "result":{"some_json":"some_value"},
747
+ "path":"system/security/role",
748
+ "api":"RoleResource#update",
749
+ "params":[{"id":2652, "name":"ADMIN_PROJECT1A"}, {}],
750
+ "method":"PUT",
751
+ "user":"ligoj-admin",
752
+ "timeout":30,
753
+ "inject": {"secret1":"value1","secret2":"value2"}
754
+ }'
755
+ ```
756
+
757
+ ### Create hook
758
+
759
+ ```bash
760
+ # Asynchronous hook
761
+ ligoj hook upsert --name "audit_role_change" --command "/home/ligoj/hooks/ligoj_audit.sh" --directory /var/log --timeout 10 --match '{"path":"system/security/role.*"}' --inject secret1 secret2
762
+
763
+ # Synchronous hook
764
+ ligoj hook upsert --name "audit_role_change" --command "/home/ligoj/hooks/ligoj_audit.sh" --directory /var/log --timeout 10 --match '{"path":"system/security/role.*", "method":"POST"}' --inject secret1 secret2 --delay 0
765
+ ```
766
+
767
+ **Note**
768
+ - For Docker image runtime, this program is executed by the container `ligoj-api`, and must be resolvable. Either this program is already packaged in the container, or it is mounted as a Docker volume to the host. Usually the mounted volume is `/home/ligoj` and points to the host path such as `/var/path/to/ligoj`. In the above hook sample, the user-level script would be `/var/path/to/ligoj/ligoj_audit.sh`.
769
+ - `--name` The human readable hook name. Is displayed in logs and HTTP headers of synchronous executions.
770
+ - `--command` The command to execute. Must be allowed by `ligoj.hook.path` configuration. This condition is checked at creation and execution time.
771
+ - `--directory` The working directory where the hook is executed.
772
+ - `--inject` Can relate to any configuration names supported by the [configuration get](#configuration) command and will be provided in the payload variable.
773
+ - `--match` Must be a valid JSON stringified object having :
774
+ * at least the `path` property relating to a valid regular expression matching to one of the available Ligoj's endpoint.
775
+ * an optional `method` property corresponding to ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"].
776
+ - `--delay` The delay in seconds before the hook is executed. Default to `1`. Use `0` for synchronous hooks.
777
+ - `--timeout` The timeout in seconds before the hook is executed. Default to `10`.
778
+
779
+ Sample executable hook script `/home/ligoj/ligoj_audit.sh`:
780
+
781
+ ```bash
782
+ #!/bin/bash
783
+ payload="$(echo "$PAYLOAD" | base64 -d)"
784
+ echo "$(echo "$payload"|jq -r '.now') $(echo "$payload"|jq -r '.method') $(echo "$payload"|jq -r '.path') [$(echo "$payload"|jq -r '.user')]" >> ligoj_audit.log
785
+ ```
786
+
787
+ For Docker runtime, to verify this hook would run as expected, try the following command from the host:
788
+
789
+ ```bash
790
+ docker exec ligoj-api jq --version
791
+ # > jq-1.6
792
+ docker exec ligoj-api python3 --version
793
+ # > Python 3.11.5
794
+ ```
795
+
796
+ ### Update hook
797
+
798
+ For update, `id` or `name` can be used. However, if `name` needs to be updated, provide the `id` as well.
799
+
800
+ ```bash
801
+ ligoj hook upsert --id 4 --name "audit_role_change_new" --command "$(pwd)/docs/sample_hook_ligoj_audit.sh" --directory /var/log --match '{"path":"system/security/role.*"}' --inject "feature:iam:node:primary" "my-secret"
802
+ ```
803
+
804
+ ### Delete hook
805
+
806
+ Deletion can be done by `id` or `name` attribute:
807
+
808
+ ```bash
809
+ ligoj hook delete --id 2
810
+ ligoj hook delete --name "audit_role_change"
811
+ ```
812
+
813
+ ### Hook get
814
+
815
+ Optional `id` or `name` filters are accepted:
816
+
817
+
818
+ ```bash
819
+ ligoj hook get
820
+ ligoj hook get --id 1
821
+ ligoj hook get --name "audit_role_change"
822
+ ```
823
+
824
+ ```json
825
+ [{"id": 1, "name": "audit_role_change", "workingDirectory": "/var/log", "command": "/path/to/ligoj_audit.sh", "match": "{\"path\":\"system/security/role.*\"}", "injects": ["java.class.path"]}]
826
+ ```
827
+
828
+
829
+ ## Plugin
830
+
831
+ ### List Ligoj plugins
832
+
833
+ ```bash
834
+ ligoj plugin list
835
+ ```
836
+
837
+ ```json
838
+ [
839
+ {
840
+ "id": "feature:ui",
841
+ "name": "Ui",
842
+ "plugin": {
843
+ "id": 4,
844
+ "createdBy": "_system",
845
+ "createdDate": 1758279349900,
846
+ "lastModifiedBy": "_system",
847
+ "lastModifiedDate": 1762277251346,
848
+ "version": "2025-10-31T14:25:16.306432087Z",
849
+ "key": "feature:ui",
850
+ "artifact": "plugin-ui",
851
+ "basePackage": "org.ligoj.app.plugin.ui",
852
+ "type": "FEATURE"
853
+ },
854
+ "location": "/path/to/ligoj-plugins/plugin-ui/target/classes/",
855
+ "deleted": false,
856
+ "nodes": 0,
857
+ "subscriptions": 0
858
+ },
859
+ ...
860
+ {
861
+ "id": "service:id:ldap",
862
+ "name": "Ldap",
863
+ "plugin": {
864
+ "id": 155,
865
+ "createdBy": "_system",
866
+ "createdDate": 1762277251427,
867
+ "lastModifiedBy": "_system",
868
+ "lastModifiedDate": 1762450362232,
869
+ "version": "2025-11-05T22:06:40.787627578Z",
870
+ "key": "service:id:ldap",
871
+ "artifact": "plugin-id-ldap",
872
+ "basePackage": "org.ligoj.app.plugin.id.ldap.resource",
873
+ "type": "TOOL"
874
+ },
875
+ "location": "/path/to/ligoj-plugins/plugin-id-ldap/target/classes/",
876
+ "nodes": 2,
877
+ "node": {
878
+ "id": "service:id:ldap",
879
+ "name": "Identity LDAP",
880
+ "refined": {"id": "service:id","name": "Identity", "mode": "create", "uiClasses": "far fa-id-badge"},
881
+ "mode": "all"
882
+ },
883
+ "subscriptions": 5
884
+ }
885
+ ]
886
+ ```
887
+
888
+ ### Install Ligoj plugins
889
+
890
+ When an explicit version is not provided, the latest version available from Maven Central is used.
891
+
892
+ This lookup depends on the `plugins.repository-manager.nexus.search` configuration, while the download relies on `plugins.repository-manager.nexus.artifact` configuration.
893
+
894
+ ```bash
895
+ ligoj plugin install --id "plugin-id" --repository "central" --version "2.2.10" --force
896
+ ligoj plugin install --id "plugin-id" --version "LATEST" --repository "nexus"
897
+ ligoj plugin install --id "plugin-id-ldap" --version "2.1.1" --repository "nexus" --force
898
+ ligoj plugin install --id "plugin-req-squash"
899
+ ligoj plugin install --id "plugin-req"
900
+ ```
901
+
902
+ ```log
903
+ [INFO ] [ligoj] Plugin 'plugin-req' has been installed/updated, a restart is required
904
+ ```
905
+
906
+ Two successful consecutive executions give this output:
907
+
908
+ ```log
909
+ [INFO ] [ligoj] Plugin 'plugin-id-ldap:2.0.3' is being installed
910
+ [INFO ] [ligoj] Plugin 'plugin-req:1.0.1' is installed but requires a restart to be available
911
+ ```
912
+
913
+ *Note* After installing plugins, a restart is needed to use them.
914
+
915
+ ### Restart API
916
+
917
+ ```bash
918
+ ligoj plugin restart
919
+ ```
920
+
921
+ ```json
922
+ null
923
+ ```
924
+
925
+ Optionally, a wait for status can be defined. A regular poll to the server [status](#status) is performed until reaching `DOWN` or `UP` status.
926
+ When different from `0`, the final status is returned.
927
+
928
+ ```bash
929
+ ligoj plugin restart --wait 20
930
+ ```
931
+
932
+ ```json
933
+ {"status": "UP"}
934
+ ```
935
+
936
+ ## Node
937
+
938
+
939
+ ### List nodes
940
+
941
+ ```bash
942
+ ligoj node list
943
+ ```
944
+
945
+ ```json
946
+ {
947
+ "recordsTotal": 23,
948
+ "recordsFiltered": 23,
949
+ "data": [
950
+ {"id": "service:build", "name": "Build", "mode": "link", "uiClasses": "fa fa-cogs", "enabled": true},
951
+ {"id": "service:build:jenkins", "name": "Jenkins", "refined": {"id": "service:build", "name": "Build", "mode": "link", "uiClasses": "fa fa-cogs"}, "mode": "all", "uiClasses": "fab fa-jenkins", "enabled": true},
952
+ ...
953
+ ]
954
+ }
955
+ ```
956
+
957
+ Optionally, parameters can be returned with provided mode and other filters
958
+
959
+ ```bash
960
+ ligoj node list --parameters-mode "all"
961
+ ligoj node list --parameters-mode "all" --search jenkins
962
+ ligoj node list --parameters-output "map" --refined "service:build:jenkins"
963
+ ```
964
+
965
+ ```json
966
+ {
967
+ "recordsTotal": 23,
968
+ "recordsFiltered": 23,
969
+ "data": [
970
+ {"id": "service:build", "name": "Build", "mode": "link", "uiClasses": "fa fa-cogs", "enabled": true, "parameters": []},
971
+ {"id": "service:build:jenkins", "name": "Jenkins", "refined": {"id": "service:build", "name": "Build", "mode": "link", "uiClasses": "fa fa-cogs"}, "mode": "all", "uiClasses": "fab fa-jenkins", "enabled": true, "parameters": []},
972
+ {"id": "service:build:jenkins:local", "name": "Jenkins Local", "refined": {"id": "service:build:jenkins", "name": "Jenkins", "refined": {"id": "service:build", "name": "Build", "mode": "link", "uiClasses": "fa fa-cogs"}, "mode": "all", "uiClasses": "fab fa-jenkins"}, "mode": "all", "enabled": true,
973
+ "parameters": [
974
+ {"text": "-secured-", "parameter": "service:build:jenkins:api-token"}, {"text": "http://localhost:9190/", "parameter": "service:build:jenkins:url"},
975
+ {"text": "-secured-", "parameter": "service:build:jenkins:user"}
976
+ ]
977
+ },
978
+ ...
979
+ ]
980
+ }
981
+ ```
982
+
983
+ ### Configure/update a node
984
+
985
+
986
+ If the related node already exists, it is updated.
987
+
988
+ ```bash
989
+ ligoj node upsert --id "service:id:ldap:remote1" --name "Remote1" --from ligoj-ldap.json
990
+ ligoj node upsert --id "service:id:ldap:remote1" --name "Remote1" --from https://path/to/ligoj-ldap.json
991
+ ```
992
+
993
+ ```json
994
+ {"id": "service:id:ldap:remote1", "name": "Remote1", "mode": "all", "enabled": true}
995
+ ```
996
+
997
+ Input `--from` JSON:
998
+ - See [`--from`](#--from) for JSON loading options
999
+ - JSON can be as list or dict (compact). See sample.
1000
+ - The parameters marked as sensitive are encrypted in database of Ligoj.
1001
+
1002
+ Content of sample [ligoj-ldap.json](docs/nodes/ldap.json) file:
1003
+
1004
+ ```json
1005
+ [
1006
+ {
1007
+ "parameter": "service:id:ldap:base-dn",
1008
+ "text": "cn=Test"
1009
+ },
1010
+ {
1011
+ "parameter": "service:id:ldap:uid-attribute",
1012
+ "text": "uid"
1013
+ }
1014
+ ]
1015
+ ```
1016
+
1017
+
1018
+ ### Get node by identifier
1019
+
1020
+ ```bash
1021
+ ligoj node get --id "service:id"
1022
+ ligoj node get --id "service:id:ldap"
1023
+ ligoj node get --id "service:id:ldap:remote1"
1024
+ ```
1025
+
1026
+ ```json
1027
+ {"id": "service:id:ldap:remote1", "name": "Remote1", "mode": "all", "enabled": true}
1028
+ ```
1029
+
1030
+ Optionally, parameters can be returned with provided mode
1031
+
1032
+ ```bash
1033
+ ligoj node get --id "service:id" --parameters-mode "all"
1034
+ ligoj node get --id "service:id:ldap" --parameters-mode "all"
1035
+ ligoj node get --id "service:id:ldap:remote1" --parameters-mode "all"
1036
+ ```
1037
+
1038
+ ```json
1039
+ {
1040
+ "id": "service:id:ldap:remote1", "name": "Remote1", "mode": "all", "enabled": true,
1041
+ "parameters": [
1042
+ {"text": "cn=Test", "parameter": "service:id:ldap:base-dn"}, {"bool": true, "parameter": "service:id:ldap:clear-password"},
1043
+ {"text": "organizationalUnit", "parameter": "service:id:ldap:companies-class"},
1044
+ {"text": "-secured-", "parameter": "service:id:ldap:user-dn"}]
1045
+ }
1046
+ ```
1047
+
1048
+ Optionally, parameters can be returned with more details
1049
+
1050
+ ```bash
1051
+ ligoj node get --id "service:id:ldap:remote1" --parameters-mode "all" --parameters-output "full"
1052
+ ```
1053
+
1054
+ ```json
1055
+ {
1056
+ "id": "service:id:ldap:remote1", "name": "Remote1", "mode": "all", "enabled": true,
1057
+ "parameters": [{
1058
+ "parameter": {
1059
+ "id": "service:id:group",
1060
+ "type": "text",
1061
+ "owner": {
1062
+ "id": "service:id",
1063
+ "name": "Identity",
1064
+ "mode": "create",
1065
+ "uiClasses": "far fa-id-badge"
1066
+ },
1067
+ "mandatory": true,
1068
+ "secured": false,
1069
+ "depends": []
1070
+ }
1071
+ },
1072
+ {
1073
+ "text": "cn=Test",
1074
+ "parameter": {
1075
+ "id": "service:id:ldap:base-dn",
1076
+ "type": "text",
1077
+ "owner": {
1078
+ "id": "service:id:ldap",
1079
+ "name": "Identity LDAP",
1080
+ "refined": {
1081
+ "id": "service:id",
1082
+ "name": "Identity",
1083
+ "mode": "create",
1084
+ "uiClasses": "far fa-id-badge"
1085
+ },
1086
+ "mode": "all"
1087
+ },
1088
+ "mandatory": false,
1089
+ "secured": false,
1090
+ "depends": []
1091
+ }
1092
+ }
1093
+ ]
1094
+ }
1095
+ ```
1096
+
1097
+ Optionally, parameter values can be decrypted. One API call is performed for each secured value.
1098
+
1099
+ This mode is only available for users having `ADMIN` role.
1100
+
1101
+ ```bash
1102
+ ligoj node get --id "service:id:ldap:remote1" --parameters-mode "all" --parameters-output map --parameters-secured
1103
+ ```
1104
+
1105
+ ```json
1106
+ {
1107
+ "id": "service:id:ldap:remote1", "name": "Remote1", "mode": "all", "enabled": true,
1108
+ "parameters": {
1109
+ "service:id:ldap:base-dn": "cn=Test",
1110
+ "service:id:ldap:clear-password": true,
1111
+ "service:id:ldap:url": "ldap:localhost:1389",
1112
+ "service:id:ldap:password": "secret",
1113
+ "service:id:ldap:companies-class": "organizationalUnit",
1114
+ "service:id:ldap:companies-dn": "ou=people,dc=sample,dc=com"
1115
+ }
1116
+ }
1117
+ ```
1118
+
1119
+ ### Get node status
1120
+
1121
+ ```bash
1122
+ ligoj node status --id "service:id:ldap:remote1"
1123
+ ```
1124
+
1125
+ ```json
1126
+ {"id": "down"}
1127
+ ```
1128
+
1129
+ ## Delegate node
1130
+
1131
+ Node delegates allow users, groups or companies to manage nodes.
1132
+
1133
+ Sub nodes inherit the delegate permissions.
1134
+
1135
+ ### List delegate nodes
1136
+
1137
+ ```bash
1138
+ ligoj delegate-node list
1139
+ ```
1140
+
1141
+ ```json
1142
+ [
1143
+ {"id": 1, "createdBy": "_system", "createdDate": 1758279349979, "lastModifiedBy": "_system", "lastModifiedDate": 1758279349979, "name": "service", "receiver": "ligoj-admin", "receiverType": "user", "canWrite": true, "canAdmin": true, "canSubscribe": true, "referenceID": "service"}
1144
+ ]
1145
+ ```
1146
+
1147
+ ### Create delegate node
1148
+
1149
+ Create a delegate with subscribe, administration, and creation rights for a receiver on an optional node and its sub-nodes.
1150
+
1151
+ The provided node does not need to exist yet.
1152
+
1153
+ ```bash
1154
+ ligoj delegate-node create --node service --can-subscribe --can-admin --can-write --receiver jdoe --receiver-type user
1155
+ ligoj delegate-node create --node service:id --can-subscribe --receiver internal --receiver-type company
1156
+ ligoj delegate-node create --node service:id:ldap:instance1 --can-admin --can-write --receiver group1 --receiver-type group
1157
+ ```
1158
+
1159
+ ### Delete delegate node
1160
+
1161
+ Delete a delegate node from its identifier.
1162
+
1163
+ ```bash
1164
+ ligoj delegate-node delete --id 1
1165
+ ```
1166
+
1167
+ ### Get a delegate node
1168
+
1169
+ Get a delegate node from its identifier.
1170
+
1171
+ ```bash
1172
+ ligoj delegate-node get --id 1
1173
+ ligoj delegate-node get --node 1
1174
+ ```
1175
+
1176
+
1177
+ ## Project
1178
+
1179
+ ### List projects
1180
+
1181
+ List projects with optional search criteria.
1182
+
1183
+ ```bash
1184
+ ligoj project list
1185
+ ligoj project list --search project1
1186
+ ```
1187
+
1188
+ ```json
1189
+ {
1190
+ "recordsTotal": 1,
1191
+ "recordsFiltered": 1,
1192
+ "data": [
1193
+ {
1194
+ "id": 153,
1195
+ "createdDate": 1705853880193, "lastModifiedDate": 1705853880193,
1196
+ "createdBy": { "id": "ligoj-admin", ...},
1197
+ "lastModifiedBy": {"id": "ligoj-admin", ...},
1198
+ "name": "Project 1",
1199
+ "teamLeader": {"id": "ligoj-admin", ...},
1200
+ "pkey": "project1",
1201
+ "description": "",
1202
+ "nbSubscriptions": 2
1203
+ },
1204
+ ...
1205
+ ]
1206
+ }
1207
+ ```
1208
+ ### Get Project
1209
+
1210
+ ```bash
1211
+ ligoj project get --id 153
1212
+ ligoj project get --id "project1"
1213
+ ```
1214
+
1215
+ ```json
1216
+ {
1217
+ "id": 153,
1218
+ "createdDate": 1705853880193, "lastModifiedDate": 1705853880193,
1219
+ "createdBy": { "id": "ligoj-admin", ...},
1220
+ "lastModifiedBy": {"id": "ligoj-admin", ...},
1221
+ "name": "Project 1",
1222
+ "teamLeader": {"id": "ligoj-admin", ...},
1223
+ "pkey": "project1",
1224
+ "description": "",
1225
+ "manageSubscriptions": true,
1226
+ "subscriptions": [
1227
+ {"id": 355, ...},
1228
+ {"id": 362, ...}
1229
+ ]
1230
+ }
1231
+ ```
1232
+
1233
+ ### Create Project
1234
+
1235
+ ```bash
1236
+ ligoj project create --name "project4" --team-leader "ligoj-admin" --pkey "sample:project4" --description "Sample project 4" --context='{"some":"value"}'
1237
+ ```
1238
+
1239
+ ```json
1240
+ {
1241
+ "id": 352,
1242
+ "creationContext": "{\"some\":\"value\"}",
1243
+ "name": "project4",
1244
+ "teamLeader": {"id": "ligoj-admin",...},
1245
+ "pkey": "sample:project4",
1246
+ "description": "Sample project 4",
1247
+ ...
1248
+ }
1249
+ ```
1250
+
1251
+ ### Delete Project
1252
+
1253
+ Delete project with optional search criteria.
1254
+
1255
+ ```bash
1256
+ ligoj project delete --id 252
1257
+ ligoj project delete --id "sample:project4"
1258
+ ligoj project delete --id "sample:project4" --with-data
1259
+ ```
1260
+
1261
+
1262
+ ## Subscription operations
1263
+
1264
+ ### List subscriptions
1265
+
1266
+ Combined filters are accepted.
1267
+
1268
+ ```bash
1269
+ ligoj subscription list --node "service:id:ldap:remote1"
1270
+ ligoj subscription list --tool "service:id:ldap"
1271
+ ligoj subscription list --service "service:id"
1272
+ ligoj subscription list --project "project1"
1273
+ ligoj subscription list --project 104
1274
+ ```
1275
+
1276
+ ```json
1277
+ [
1278
+ {"id": 155, "node": "service:id:ldap:remote1", "project": 104},
1279
+ {"id": 302, "node": "service:qa:sonarqube:8", "project": 104}
1280
+ ]
1281
+ ```
1282
+
1283
+ ### Get subscription details
1284
+
1285
+ ```bash
1286
+ ligoj subscription get --id 302
1287
+ ```
1288
+
1289
+ ```json
1290
+ {"service:qa:sonarqube:project": "test", "service:qa:sonarqube:url": "http://127.0.0.1:9000/"}
1291
+ ```
1292
+
1293
+ #### With related project and node details
1294
+
1295
+ ```bash
1296
+ ligoj subscription get --id 302 --details
1297
+ ```
1298
+
1299
+ ```json
1300
+ {"subscription": 302, "project": {"id": 104, "name": "Project1", "description": "Foo bar"}, "parameters": {"service:qa:sonarqube:project": "test", "service:qa:sonarqube:url": "http://127.0.0.1:9000/"}, "node": {"id": "service:qa:sonarqube:8", "name": "Sonar Local 8", "refined": {"id": "service:qa:sonarqube", "name": "SonarQube", "refined": {"id": "service:qa", "name": "Quality Assurance", "mode": "link", "uiClasses": "fas fa-tachometer-alt"}, "mode": "link"}, "mode": "link", "enabled": true}}
1301
+ ```
1302
+
1303
+ ### Create subscription
1304
+
1305
+ Configuration file can be a JSON file, a remote HTTP URL, or plain JSON. Both forms of parameters are accepted, as list or dict (compact).
1306
+
1307
+ Duplicate subscriptions are ignored: same project, node and parameters.
1308
+
1309
+ ```bash
1310
+ ligoj subscription create --project project1 --node "service:id:ldap:remote1" --from conf.json
1311
+ ligoj subscription create --project project1 --node "service:id:ldap:remote1" --from "https://path/to/conf.json"
1312
+ ligoj subscription create --project project1 --node "service:id:ldap:remote1" --from '[{"parameter": "service:id:group", "text": "project1-team"}, {"parameter": "service:id:ou", "text": "project1"}]'
1313
+ ligoj subscription create --project project1 --node "service:id:ldap:remote1" --from '{"service:id:group": "project1-team", "service:id:ou": "project1"}'
1314
+ ...
1315
+ ```
1316
+
1317
+ ```json
1318
+ 362
1319
+ ```
1320
+
1321
+ Input `--from` JSON:
1322
+ - See [`--from`](#--from) for JSON loading options
1323
+ - JSON can be as list or dict (compact). See sample.
1324
+ - The parameters marked as sensitive are encrypted in database of Ligoj.
1325
+
1326
+ ### Delete a subscription
1327
+
1328
+ Delete a subscription from its identifier.
1329
+
1330
+
1331
+ ```bash
1332
+ ligoj subscription delete --id 302
1333
+ ```
1334
+
1335
+ By default, only the link between Ligoj and the remote tool is removed. Optionally, when Ligoj has created data with the subscription, it can also be deleted with this operation.
1336
+
1337
+ For example, LDAP groups or a Jenkins job created at subscription time will be deleted.
1338
+
1339
+ ```bash
1340
+ ligoj subscription delete --id 302 --with-data
1341
+ ```
1342
+
1343
+ ### Get subscription statuses of a project
1344
+
1345
+ Return the last computed status of all subscriptions of given project.
1346
+
1347
+ ```bash
1348
+ ligoj subscription status --project 104
1349
+ ligoj subscription status --project project1
1350
+ ```
1351
+
1352
+ ```json
1353
+ {
1354
+ "155": {"specifics": [], "value": "UP", "type": "status", "node": {"id": "service:id:ldap:remote1", "name": "TestAnnuaireCLI", "mode": "all"}, "subscription": 155},
1355
+ "252": {"specifics": [], "value": "DOWN", "type": "status", "node": {"id": "service:qa:sonarqube:user", "name": "Sonar Local User", "mode": "link"}, "subscription": 252},
1356
+ "157": {"specifics": [], "value": "UP", "type": "status", "node": {"id": "service:id:ldap:remote1", "name": "TestAnnuaireCLI", "mode": "all"}, "subscription": 157}
1357
+ }
1358
+ ```
1359
+
1360
+ ### Request subscription status refresh
1361
+
1362
+ Retrieve the up-to-date status of a subscription.
1363
+
1364
+
1365
+ Up subscription:
1366
+
1367
+ ```bash
1368
+ ligoj subscription refresh --id 155
1369
+ ```
1370
+
1371
+ ```json
1372
+ {"id": 155, "status": "up", "node": "service:id:ldap:remote1", "project": 104, "data": {"members": 0}, "parameters": {...}}
1373
+ ```
1374
+
1375
+ Down subscription:
1376
+ ```bash
1377
+ ligoj subscription refresh --id 252
1378
+ ```
1379
+
1380
+ ```json
1381
+ {"id": 252, "status": "down", "project": 104, "data": {}, "parameters": {"service:qa:sonarqube:project": "test",...}}
1382
+ ```
1383
+
1384
+
1385
+ # Plugin id
1386
+
1387
+ Operations related to [plugin-id](https://github.com/ligoj/plugin-id) and sub-plugins.
1388
+
1389
+
1390
+ ## Plugin `id:scope` operations
1391
+
1392
+ Operations related to container scopes managed by `service:id` nodes.
1393
+
1394
+
1395
+ ### Create container scope
1396
+
1397
+ Create a container scope
1398
+
1399
+ ```bash
1400
+ ligoj id:scope create --id "Unassigned" --type "group" --dn "ou=groups,dc=example,dc=com"
1401
+ ligoj id:scope create --id "Projects" --type "group" --dn "ou=projects,ou=groups,dc=example,dc=com"
1402
+ ligoj id:scope create --id "Tools" --type "group" --dn "ou=tools,ou=groups,dc=example,dc=com"
1403
+ ligoj id:scope create --id "Unassigned" --type "company" --dn "ou=people,dc=example,dc=com"
1404
+ ligoj id:scope create --id "Internal" --type "company" --dn "ou=internal,ou=people,dc=example,dc=com"
1405
+ ligoj id:scope create --id "Unassigned" --type "tree" --dn "dc=example,dc=com"
1406
+ ```
1407
+
1408
+
1409
+ ### Get container scope
1410
+
1411
+ Return a container scope
1412
+
1413
+ ```bash
1414
+ ligoj id:scope get --id "SampleGroup2"
1415
+ ```
1416
+
1417
+ ```json
1418
+ {"id": "samplegroup2", "name": "SampleGroup2", "scope": "Unassigned", "locked": false}
1419
+ ```
1420
+
1421
+
1422
+ ### List container scopes
1423
+
1424
+ Return a list of container scopes
1425
+
1426
+ ```bash
1427
+ ligoj id:scope list --type "group"
1428
+ ```
1429
+
1430
+ ```json
1431
+ {
1432
+ "recordsTotal": 4, "recordsFiltered": 3,
1433
+ "data": [
1434
+ {"id": 5, "name": "Unassigned", "dn": "ou=groups,dc=sample,dc=com", "type": "group", "locked": false},
1435
+ {"id": 6, "name": "Project", "dn": "ou=projects,ou=groups,dc=sample,dc=com", "type": "group", "locked": false},
1436
+ {"id": 7, "name": "Technical", "dn": "ou=tools,ou=groups,dc=sample,dc=com", "type": "group", "locked": false}
1437
+ ]
1438
+ }
1439
+ ```
1440
+
1441
+ ## Plugin `id:group` operations
1442
+
1443
+ Operations related to groups managed by `service:id` nodes
1444
+
1445
+ Group name is case insensitive.
1446
+
1447
+
1448
+ ### Create group
1449
+
1450
+ Create a group.
1451
+
1452
+
1453
+ ```bash
1454
+ ligoj id:group create --name "SampleGroup2" --scope "Unassigned"
1455
+ ```
1456
+
1457
+ Create a group inside a group
1458
+
1459
+ ```bash
1460
+ ligoj id:group create --name "SampleSubGroup" --scope "Unassigned" --parent "SampleGroup2"
1461
+ ligoj id:group create --name "SampleSubGroup2" --scope "Unassigned" --parent "SampleSubGroup"
1462
+ ```
1463
+
1464
+
1465
+ ### Delete a group
1466
+
1467
+ Delete a group. The command will not fail if the group does not exist.
1468
+
1469
+ ```bash
1470
+ ligoj id:group delete --name "SampleGroup2"
1471
+ ```
1472
+
1473
+
1474
+ ### Get group
1475
+
1476
+ Retrieve a group
1477
+
1478
+ ```bash
1479
+ ligoj id:group get --name "SampleGroup2"
1480
+ ```
1481
+
1482
+ ```json
1483
+ {"id": "samplegroup2", "name": "SampleGroup2", "scope": "Unassigned", "locked": false}
1484
+ ```
1485
+
1486
+ ### Delete group
1487
+
1488
+ Delete a group. If the group does not exist, the command will not return an error.
1489
+
1490
+ ```bash
1491
+ ligoj id:group delete --name "SampleGroup2"
1492
+ ```
1493
+
1494
+
1495
+ ### List group
1496
+
1497
+ List groups
1498
+
1499
+ ```bash
1500
+ ligoj id:group list
1501
+ ```
1502
+
1503
+ ```json
1504
+ {
1505
+ "recordsTotal": 4,
1506
+ "recordsFiltered": 4,
1507
+ "data": [
1508
+ {
1509
+ "id": "sample group",
1510
+ "name": "Sample Group",
1511
+ "scope": "Unassigned",
1512
+ "locked": false,
1513
+ "countVisible": 3,
1514
+ "count": 3,
1515
+ "canWrite": true,
1516
+ "canAdmin": true,
1517
+ "containerType": "group"
1518
+ },
1519
+ {
1520
+ "id": "samplegroup2",
1521
+ "name": "SampleGroup2",
1522
+ "scope": "Unassigned",
1523
+ "locked": false,
1524
+ "countVisible": 0,
1525
+ "count": 0,
1526
+ "canWrite": true,
1527
+ "canAdmin": true,
1528
+ "containerType": "group"
1529
+ },
1530
+ {
1531
+ "id": "samplesubgroup",
1532
+ "name": "SampleSubGroup",
1533
+ "scope": "Unassigned",
1534
+ "locked": false,
1535
+ "countVisible": 0,
1536
+ "count": 0,
1537
+ "canWrite": true,
1538
+ "canAdmin": true,
1539
+ "containerType": "group",
1540
+ "parents": [
1541
+ "samplegroup2"
1542
+ ]
1543
+ },
1544
+ {
1545
+ "id": "samplesubgroup2",
1546
+ "name": "SampleSubGroup2",
1547
+ "scope": "Unassigned",
1548
+ "locked": false,
1549
+ "countVisible": 0,
1550
+ "count": 0,
1551
+ "canWrite": true,
1552
+ "canAdmin": true,
1553
+ "containerType": "group",
1554
+ "parents": [
1555
+ "samplesubgroup",
1556
+ "samplegroup2"
1557
+ ]
1558
+ }
1559
+ ]
1560
+ }
1561
+ ```
1562
+
1563
+ ## Plugin `id:user` operations
1564
+
1565
+ Operations related to users managed by `service:id` nodes
1566
+
1567
+
1568
+ ### Create user
1569
+
1570
+ ```bash
1571
+ ligoj id:user create --id jdupont --firstname "Jean" --lastname "Dupont" --mail "jdupont@kloudy.io" --company "external" --groups "Sample Group,SampleGroup2"
1572
+ ligoj id:user create --id jdupont2 --firstname "Jean" --lastname "Dupont" --mail "jdupont@kloudy.io" --company "external" --groups "Sample Group,SampleGroup2"
1573
+ ```
1574
+
1575
+ ### Delete user
1576
+
1577
+ Delete a user. If the user does not exist, the command will not return an error.
1578
+
1579
+ ```bash
1580
+ ligoj id:user delete --id jdupont2
1581
+ ligoj id:user delete --mail jdupont@kloudy.io
1582
+ ```
1583
+
1584
+ ### List users
1585
+
1586
+ ```bash
1587
+ ligoj id:user list
1588
+ ligoj id:user list --company "department1" --group "Sample Group" --criteria "@sample.com" --page-length 2
1589
+ ligoj id:user list --company "department1" --page-length 2
1590
+ ```
1591
+
1592
+ ```json
1593
+ {
1594
+ "recordsTotal": 102,
1595
+ "recordsFiltered": 102,
1596
+ "extensions": {"customAttributes": ["uidFonctionnel"]}},
1597
+ "data": [
1598
+ {"firstName": "John", "lastName": "Doe", "id": "jdoe", "company": "external", "mails": ["jdoe@sample.com"], "groups": ["Sample Group", "SampleGroup2"], "name": "jdoe"},
1599
+ {"firstName": "Cli2", "lastName": "Name", "id": "cli2name", "company": "external", "mails": ["a@bc.org","cli2@sample.com"], "groups": ["Sample Group"], "name": "cli2name"}
1600
+ ]
1601
+ }
1602
+ ```
1603
+ ### Get user
1604
+
1605
+ Return a user. If the user does not exist, the command will return `null`.
1606
+
1607
+ ```bash
1608
+ ligoj id:user get --id jdupont
1609
+ ligoj id:user get --mail jdupont@kloudy.io
1610
+ ```
1611
+
1612
+ ```json
1613
+ {"firstName": "Jean", "lastName": "Dupont", "id": "jdupont", "company": "external", "mails": ["jdupont@kloudy.io"], "groups": ["Sample Group", "SampleGroup2"], "name": "jdupont"}
1614
+ ```
1615
+
1616
+ ### Add user to a group
1617
+
1618
+ The user and the group must exist.
1619
+ The command does not fail if the user is already in the group.
1620
+
1621
+ ```bash
1622
+ ligoj id:user add --id jdupont --groups "SampleGroup2"
1623
+ ligoj id:user add --mail jdupont@kloudy.io --groups "SampleGroup2"
1624
+ ligoj id:user add --mail cli10.name@sample.com --groups "Sample Group"
1625
+ ```
1626
+
1627
+ ### Remove user from a group
1628
+
1629
+ The user and the group must exist.
1630
+ The command does not fail if the user is not in the group.
1631
+
1632
+ ```bash
1633
+ ligoj id:user remove --id jdupont --groups "SampleGroup2"
1634
+ ligoj id:user remove --mail jdupont@kloudy.io --groups "SampleGroup2"
1635
+ ```
1636
+
1637
+ ### Reset user password
1638
+
1639
+ For a specific user (need administrative rights):
1640
+
1641
+ The user must exist.
1642
+
1643
+ ```bash
1644
+ ligoj id:user reset-password --id jdupont
1645
+ ligoj id:user reset-password --mail jdupont@kloudy.io
1646
+ ```
1647
+
1648
+ For current user:
1649
+
1650
+ ```bash
1651
+ ligoj id:user reset-password
1652
+ ```
1653
+
1654
+ # Bootstrap
1655
+
1656
+ The following commands can be executed to perform several API commands following a complex workflow.
1657
+
1658
+ Most bootstrap arguments like `--jenkins-endpoint`, corresponding [configuration file](#configuration-files) option such as `jenkins_endpoint` is accepted, and environment variable `JENKINS_ENDPOINT` too.
1659
+
1660
+
1661
+ ## Bootstrap `init`
1662
+
1663
+ Initialize Ligoj with basic group management, containers, and companies hierarchy.
1664
+
1665
+ Sample Docker command:
1666
+
1667
+ ```bash
1668
+ ligoj bootstrap init --base-dn="dc=sample,dc=com"
1669
+ ```
1670
+
1671
+ *Note* `--base-dn` argument can also be defined as `ligoj_ldap_base_dn` in [configuration file](#configuration-files) and `LIGOJ_LDAP_BASE_DN` environment variable.
1672
+
1673
+
1674
+ Hierarchy tree sample for base DN `dc=sample,dc=com`
1675
+
1676
+
1677
+ | DN LDAP | Scope name | Scope type |
1678
+ | ------------------------------------------------------------------------------------ | ------------ | ---------- |
1679
+ | `ou=people` | `Unassigned` | `company` |
1680
+ | ` ou=technical-users,ou=people` | `Technical` | `company` |
1681
+ | ` ou=external,ou=people` | `External` | `company` |
1682
+ | `ou=groups` | `Unassigned` | `group` |
1683
+ | ` ou=projects,ou=groups` | `Project` | `group` |
1684
+ | ` ou=tools,ou=groups` | `Technical` | `group` |
1685
+ | ` cn=jenkins-administrators,ou=tools,ou=groups` | (inherited) | `group` |
1686
+ | ` cn=nexus-administrators,ou=tools,ou=groups` | (inherited) | `group` |
1687
+ | ` cn=nexus-administrators-paris,cn=nexus-administrators,ou=tools,ou=groups` | (inherited) | `group` |
1688
+ | ` cn=nexus-administrators-paris-8,cn=nexus-administrators,ou=tools,ou=groups` | (inherited) | `group` |
1689
+
1690
+
1691
+ ### Via `ligoj bootstrap init`
1692
+
1693
+ ```bash
1694
+ ligoj bootstrap init --base-dn="dc=sample,dc=com" --users-base-dn "ou=people" --internal-users-base-dn "" --technical-users-base-dn "ou=technical-users" --external-users-base-dn "ou=external" --groups-base-dn "ou=groups" --technical-groups-base-dn "ou=tools" --projects-base-dn "ou=projects" --technical-groups "sonar-administrators" "jenkins-administrators" "nexus-administrators"
1695
+ ```
1696
+
1697
+ ### Via `ligoj id` commands
1698
+
1699
+ ```bash
1700
+ ## Users and companies
1701
+
1702
+ ### OU LDAP intermediate
1703
+ ligoj id:ou create --name "people" --parent-dn "dc=sample,dc=com"
1704
+ ligoj id:ou create --name "external" --parent-dn "ou=people,dc=sample,dc=com"
1705
+ ligoj id:ou create --name "technical-users" --parent-dn "ou=people,dc=sample,dc=com"
1706
+
1707
+ ### Companies
1708
+ ligoj id:scope create --name "Unassigned" --type "company" --dn "ou=people,dc=sample,dc=com"
1709
+ ligoj id:scope create --name "External" --type "company" --dn "ou=external,ou=people,dc=sample,dc=com"
1710
+ ligoj id:scope create --name "Technical" --type "company" --dn "ou=technical-users,ou=people,dc=sample,dc=com"
1711
+
1712
+ ## Groups
1713
+
1714
+ ### OU LDAP intermediate
1715
+ ligoj id:ou create --name "groups" --parent-dn "dc=sample,dc=com"
1716
+ ligoj id:ou create --name "projects" --parent-dn "ou=groups,dc=sample,dc=com"
1717
+ ligoj id:ou create --name "tools" --parent-dn "ou=groups,dc=sample,dc=com"
1718
+
1719
+ ### Scope functionals for groups
1720
+ ligoj id:scope create --name "Unassigned" --type "group" --dn "ou=groups,dc=sample,dc=com"
1721
+ ligoj id:scope create --name "Project" --type "group" --dn "ou=projects,ou=groups,dc=sample,dc=com"
1722
+ ligoj id:scope create --name "Technical" --type "group" --dn "ou=tools,ou=groups,dc=sample,dc=com"
1723
+
1724
+ ### Technical groups and sub-groups
1725
+ ligoj id:group create --name "jenkins-administrators" --scope "Technical"
1726
+ ligoj id:group create --name "nexus-administrators" --scope "Technical"
1727
+ ligoj id:group create --name "nexus-administrators-paris" --scope "Technical" --parent "nexus-administrators"
1728
+ ligoj id:group create --name "nexus-administrators-paris-8" --scope "Technical" --parent "nexus-administrators-paris"
1729
+ ```
1730
+
1731
+
1732
+ ## Bootstrap `welcome-user`
1733
+
1734
+ Configure a new project and its administrator.
1735
+
1736
+ ![Sequence](docs/bootstrap/welcome-user.png)
1737
+
1738
+ ```bash
1739
+ ligoj bootstrap welcome-user --id jdupont --project project1 --name "Project 1" --group-suffix="-team"
1740
+ ```
1741
+
1742
+ Optionally, the project key can be validated with DNS within a defined DNS zone :
1743
+
1744
+ ```bash
1745
+ ligoj bootstrap welcome-user --id jdupont --project project1 --name "PIProject 1" --verify-project-with-dns "PROJECT_KEY.holder.kloudy.io,PROJECT_KEY.holder2.kloudy.io" --group-suffix="-team"
1746
+ ```
1747
+
1748
+ ```json
1749
+ {
1750
+ "admin_user": "jdupont",
1751
+ "script_user": "project1-script",
1752
+ "script_api_key": "...",
1753
+ "reader_user": "project1-reader",
1754
+ "reader_password": "...",
1755
+ "project_key": "project1",
1756
+ "project_id": 6552
1757
+ }
1758
+ ```
1759
+
1760
+ Optionally, Ligoj nodes such as Jenkins and SonarQube can be created during this step.
1761
+
1762
+ ```bash
1763
+ ligoj bootstrap welcome-user --id jdupont --project project1 --name "Project 1" --verify-project-with-dns "PROJECT_KEY.holder.kloudy.io,PROJECT_KEY.holder2.kloudy.io" --group-suffix="-team" --jenkins-create-node --jenkins-endpoint http://localhost:8086 --jenkins-api-token="" --sonar-create-node --sonar-endpoint http://localhost:9000 --sonar-api-token="" --reset-reader-password
1764
+ ```
1765
+
1766
+ *Notes*
1767
+ - `reader_password` result is provided only for new user and cannot be retrieved by Ligoj.
1768
+ - To generate another password, use the `--reset-reader-password` flag.
1769
+ - `reader_password` (or reset password) is used to create API tokens saved in Ligoj nodes
1770
+ - `--jenkins-api-token` and `--sonar-api-token` can be provided with this command but should be related to the `reader_user` or `--jenkins-api-user` value.
1771
+ - All endpoints and tokens are also sourced from [configuration file](#configuration-files) and environment variables.
1772
+
1773
+ ## Bootstrap `create-project`
1774
+
1775
+ Create new groups within a new project related to another one.
1776
+
1777
+ Considering this use case :
1778
+ - Create a new project having `project-a` as key and `Project A` as name.
1779
+ - Team leader (administrator) will be `cli100.name@sample.com`. Actual username is resolved automatically from email.
1780
+ - Initial groups within this project are `admin`, `dev` and `test`.
1781
+ - The parent project's key (used as context) is `project1`. This project must be managed by the user: `ligoj-user`
1782
+
1783
+ The corresponding command is:
1784
+
1785
+ ```bash
1786
+ ligoj bootstrap create-project --project project-a --name "Project A" --groups "admin" "dev" "test" \
1787
+ --parent-project "project1" \
1788
+ --parent-admin "ligoj-user" \
1789
+ --team-leader cli100.name@sample.com \
1790
+ ```
1791
+
1792
+ *Note* When `parent-admin` is provided, this operation exploits the `run-as` feature of Ligoj to check the administrator of `parent-project`. In such a case, the session user must be a system administrator.
1793
+
1794
+
1795
+ ## Bootstrap `delete-project`
1796
+
1797
+ Delete a project including all groups, not only the references.
1798
+
1799
+ ```bash
1800
+ ligoj bootstrap delete-project --project project-a --parent-admin "ligoj-user"
1801
+ ```
1802
+
1803
+ *Note* When `parent-admin` is provided, this operation exploits the `run-as` feature of Ligoj to check the administrator of `parent-project`. In such a case, the session user must be a system administrator.
1804
+
1805
+ ## Bootstrap create-roles
1806
+
1807
+ Create mapped roles in various tools
1808
+
1809
+ Supported services are:
1810
+ - Jenkins
1811
+ - SonarQube
1812
+ - Nexus
1813
+ - Alfresco
1814
+ - GitLab
1815
+
1816
+ ![Sequence](docs/bootstrap/create-roles.png)
1817
+
1818
+
1819
+ Created contents by tools
1820
+
1821
+ | Tool | Content type | Note |
1822
+ | --------------------------------- | ----------------------- | ----------------------------------------------------- |
1823
+ | [Jenkins](#jenkins) | Folder RBAC Permissions | See [CasC notes](#security-and-configuration-as-code) |
1824
+ | [Jenkins](#jenkins) | Global RBAC Permissions | See [CasC notes](#security-and-configuration-as-code) |
1825
+ | [Jenkins](#jenkins) | Folder credentials | See [supported credentials](#credentials) |
1826
+ | [Jenkins](#jenkins) | Global credentials | See [supported credentials](#credentials) |
1827
+ | [Jenkins](#jenkins) | Folders | Nested `folders` structure supported |
1828
+ | [SonarQube](#sonarqube) | Groups and RBAC | |
1829
+ | [SonarQube](#sonarqube) | Projects | |
1830
+ | [SonarQube](#sonarqube) | Templates | |
1831
+ | [GitLab](#gitLab) | Wrapper project Groups | |
1832
+ | [GitLab](#gitLab) | LDAP project Groups | |
1833
+ | [GitLab](#gitLab) | Project Groups | |
1834
+ | [Sonatype Nexus](#sonatype-nexus) | Roles | |
1835
+ | [Sonatype Nexus](#sonatype-nexus) | Repositories | |
1836
+ | [Alfresco](#alfresco) | Roles | |
1837
+ | [Alfresco](#alfresco) | Sites | |
1838
+ | [ArgoCD](#argocd) | Permissions | Optional `permission=deny` and `application` scope |
1839
+ | [ArgoCD](#argocd) | Projects | |
1840
+ | [Harbor](#harbor) | Projects | |
1841
+ | [Harbor](#harbor) | Projects members | |
1842
+
1843
+
1844
+ Group and role configuration [JSON file conf.json](docs/bootstrap/create-roles.json).
1845
+ See [`--from`](#--from) for JSON loading options
1846
+
1847
+ ```bash
1848
+ ligoj bootstrap create-roles --project project-a --from conf.json \
1849
+ --argocd-token="$ARGOCD_TOKEN" \
1850
+ --argocd-user="$ARGOCD_USER" \
1851
+ --alfresco-endpoint="$ALFRESCO_ENDPOINT" \
1852
+ --alfresco-user="$ALFRESCO_USER" \
1853
+ --alfresco-password="$ALFRESCO_PASSWORD" \
1854
+ --nexus-endpoint="$NEXUS_ENDPOINT" \
1855
+ --nexus-user="$NEXUS_USER" \
1856
+ --nexus-password="$NEXUS_PASSWORD" \
1857
+ --gitlab-endpoint="$GITLAB_ENDPOINT" \
1858
+ --gitlab-token="$GITLAB_TOKEN" \
1859
+ --jenkins-home="$JENKINS_HOME" \
1860
+ --jenkins-endpoint="$JENKINS_ENDPOINT" \
1861
+ --sonar-endpoint="$SONAR_ENDPOINT" \
1862
+ --sonar-api-token="$SONAR_API_KEY" \
1863
+ --harbor-endpoint="$HARBOR_ENDPOINT" \
1864
+ --harbor-user="$HARBOR_USER" \
1865
+ --harbor-password="$HARBOR_PASSWORD"
1866
+ ```
1867
+
1868
+ ```bash
1869
+ ligoj bootstrap create-roles --project project-a --from "https://path/to/conf.json"
1870
+ ```
1871
+
1872
+ ```bash
1873
+ ligoj bootstrap create-roles --project project-a --from '[{"text": "organizationalUnit","parameter": "service:id:ldap:companies-class"},...]'
1874
+ ```
1875
+
1876
+ For detailed tool specific options, execute usage command:
1877
+
1878
+ ```bash
1879
+ ligoj bootstrap create-roles --help
1880
+ ```
1881
+
1882
+ ```log
1883
+ usage: Ligoj CLI bootstrap create-roles [-h] [--project PROJECT] [--group-suffix GROUP_SUFFIX] [--groups [GROUPS ...]] [--from FROM]
1884
+ [--schema SCHEMA]
1885
+ [--alfresco-endpoint ALFRESCO_ENDPOINT] [--alfresco-user ALFRESCO_USER] [--alfresco-password ALFRESCO_PASSWORD]
1886
+ [--alfresco-ticket ALFRESCO_TICKET]
1887
+ [--gitlab-endpoint GITLAB_ENDPOINT] [--gitlab-token GITLAB_TOKEN] [--gitlab-base-group GITLAB_BASE_GROUP]
1888
+ [--gitlab-project-group-prefix GITLAB_PROJECT_GROUP_PREFIX] [--gitlab-project-subgroup-prefix GITLAB_PROJECT_SUBGROUP_PREFIX]
1889
+ [--jenkins-home JENKINS_HOME] [--jenkins-crumb JENKINS_CRUMB] [--jenkins-endpoint JENKINS_ENDPOINT]
1890
+ [--jenkins-api-user JENKINS_API_USER] [--jenkins-api-token JENKINS_API_TOKEN]
1891
+ ...
1892
+
1893
+ options:
1894
+ -h, --help show this help message and exit
1895
+ --project PROJECT, -p PROJECT
1896
+ Associated project key
1897
+ ...
1898
+ ```
1899
+
1900
+ ### `--includes` and `--excludes` options
1901
+
1902
+ Each supported tool can be included or excluded from the bootstrap commands:
1903
+ - By default, all discovered JSON's content is considered, no exclusion. Implicit `--includes "*"`.
1904
+ - Special value `*` means all.
1905
+ - Multiple `includes` and `excludes` values can be provided
1906
+ - The `excludes` option has higher priority than `includes`.
1907
+ - When the resolved endpoint is empty or null, the tool is ignored.
1908
+
1909
+
1910
+ ### Constraints
1911
+
1912
+ Checked constraints:
1913
+ - Referenced groups must be defined at root level. This constraint ensures a correct definition and avoids typos.
1914
+ - Empty permissions set are not allowed.
1915
+ - Given JSON must validate the [JSON Schema](https://json-schema.org/) [document schema.json](./schema.json).
1916
+ - [JSON Schema](https://json-schema.org/) can be merged with custom additions: `--schema "JSON Schema string, file or URL"`.
1917
+
1918
+ Sample constraint limiting Alfresco sites to `1`: `--schema='{"properties":{"alfresco":{"properties":{"sites":{"maxItems": 1}}}}}'`
1919
+
1920
+ ### Jenkins
1921
+
1922
+ Supported resources are:
1923
+ - Nested folders
1924
+ - Credentials with or without values
1925
+ - Roles, group mapping and permissions, at folder or global level
1926
+
1927
+
1928
+ #### Configuration
1929
+
1930
+ | Parameter | Environment variable | Note | Default |
1931
+ | --------------------- | -------------------- | ---------------------------------------------- | --------------- |
1932
+ | `--jenkins-endpoint` | `JENKINS_ENDPOINT` | HTTPS endpoint | Current Jenkins |
1933
+ | `--jenkins-api-user` | `JENKINS_API_USER` | Username | |
1934
+ | `--jenkins-api-token` | `JENKINS_API_TOKEN` | Token generated from `/user/_me_/configure` | |
1935
+ | | | Sourced from Jenkins credential `JENKINS_API`. | |
1936
+ | `--jenkins-home` | `JENKINS_HOME` | JENKINS home location for CasC update | |
1937
+ | `--jenkins-crumb` | `JENKINS_CRUMB` | Crumb protection enablement | `auto` |
1938
+
1939
+ #### Folders
1940
+
1941
+ - Recursive folders are supported; however, each folder must be unique. This is not an implementation limit, but it makes folder reorganization possible.
1942
+ - Folder maximal depth is `4`, but it is not a hard limit
1943
+ - Folder names are encoded, special chars are supported
1944
+ - Supported folder types are `com.cloudbees.hudson.plugins.folder.Folder` and `jenkins.branch.OrganizationFolder`. Folder mode update is not supported. Other folder modes *might* work, but have not been tested.
1945
+ - There is no [permission](https://www.jenkins.io/doc/book/security/access-control/permissions/#optional-permissions) limitation; internal identifiers must be used, such as `hudson.model.Item.Build`, `hudson.model.Hudson.Administer`, etc.:
1946
+ - [Overall permissions](https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/security/Permission.java)
1947
+ - [Run permissions](https://github.com/jenkinsci/jenkins/blob/3bc62eeae933c86f6a94c940fe6f35882f1e29d5/core/src/main/java/hudson/model/Run.java#LL2593C7-L2593C7)
1948
+ - [Item permissions](https://github.com/jenkinsci/jenkins/blob/3bc62eeae933c86f6a94c940fe6f35882f1e29d5/core/src/main/java/hudson/model/Item.java#L252)
1949
+ - [SCM permissions](https://github.com/jenkinsci/jenkins/blob/3bc62eeae933c86f6a94c940fe6f35882f1e29d5/core/src/main/java/hudson/scm/SCM.java#L761)
1950
+ - [Credential permissions](https://github.com/jenkinsci/credentials-plugin/blob/b96f366e7badeedaf69724991e44409be11a07b6/src/main/java/com/cloudbees/plugins/credentials/CredentialsProvider.java#L185)
1951
+ - The naming convention for permissions is the full class name, followed by the field ([Permission](https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/security/Permission.java)) name converted to Camel case, e.g., `hudson.model.View.Read`
1952
+
1953
+ #### Credentials
1954
+
1955
+ There is no limitation for credentials type, the supported configuration is:
1956
+ - Any parameter type but file
1957
+ - Tested types are:
1958
+ - `com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl`
1959
+ - `org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl`
1960
+ - `com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey`
1961
+ - Supported `scope` values are `global` and `system` (case insensitive). When not provided, the default behavior of this credential type is applied.
1962
+ - Attached domain is always `All domains`: `_`
1963
+
1964
+
1965
+ #### Security and Configuration as Code
1966
+
1967
+ Requires the installed, configured and assigned Jenkins plugin [Role-based Authorization Strategy](https://plugins.jenkins.io/role-strategy/).
1968
+ Underlying [role management API](https://javadoc.jenkins.io/plugin/role-strategy/com/michelin/cio/hudson/plugins/rolestrategy/RoleBasedAuthorizationStrategy.html) is executed.
1969
+
1970
+ CaC (Configuration as Code) [YAML file]($JENKINS_HOME/jenkins.yaml) management is supported:
1971
+ - CaC file location override support is `JENKINS_CASC_FILE` variable, then `CASC_JENKINS_CONFIG` variable, then `$JENKINS_HOME/jenkins.yaml` as default.
1972
+ - Only update mode is supported after all API calls, not creation
1973
+ - Both current and in-memory CaC files YAML structure must contain this path: `jenkins.authorizationStrategy.roleBased.roles`
1974
+ - Both current and in-memory CaC files YAML structure must contain this path: `jenkins.securityRealm.ldap.configurations`
1975
+ - The script must be able to write the backup file `$path_to_cac_file.ligoj`, which will be overwritten.
1976
+ - A unified diff is computed and printed for current and in-memory CaC files
1977
+ - Backup and update are executed only if there is at least one change detected in the computed unified diff
1978
+ - By default, the related sub-folder access is granted from the parent folder, and the related pattern is suffixed with the `(/.*)?` expression. Set `recursive` to `false` to block this behavior.
1979
+ - Roles use the folder identifier, case is insensitive
1980
+
1981
+ ``` yml
1982
+ securityRealm:
1983
+ ldap:
1984
+ configurations:
1985
+ - displayNameAttributeName: "cn"
1986
+ groupMembershipStrategy:
1987
+ fromGroupSearch:
1988
+ filter: "(| (member={0}) (uniqueMember={0}) (memberUid={1}))"
1989
+ groupSearchBase: "ou=groups"
1990
+ groupSearchFilter: "(& (cn={0}) (| (objectClass=groupOfNames) (objectClass=groupOfUniqueNames)\
1991
+ \ (objectClass=posixGroup)))"
1992
+ inhibitInferRootDN: false
1993
+ managerDN: "cn=Manager,dc=sample,dc=com"
1994
+ managerPasswordSecret: "{...}"
1995
+ rootDN: "dc=sample,dc=com"
1996
+ server: "ldap://localhost:1389"
1997
+ userSearchBase: "ou=people"
1998
+ disableMailAddressResolver: false
1999
+ disableRolePrefixing: true
2000
+ groupIdStrategy: "caseInsensitive"
2001
+ userIdStrategy: "caseInsensitive"
2002
+ ```
2003
+
2004
+
2005
+ ### SonarQube
2006
+
2007
+ Supported resources are:
2008
+ - Projects
2009
+ - Template
2010
+ - Roles, group mapping and permissions, at project or global level
2011
+
2012
+
2013
+ #### Configuration
2014
+
2015
+ | Parameter | Environment variable | Note |
2016
+ | ------------------- | -------------------- | ---------------------------------------------- |
2017
+ | `--sonar-endpoint` | `SONAR_ENDPOINT` | HTTPS endpoint |
2018
+ | | | Sourced from Jenkins build parameter. |
2019
+ | `--sonar-api-token` | `SONAR_API_TOKEN` | API key generated from `/account/security` API |
2020
+ | | | - Type is `User Token` |
2021
+ | | | - User rights : `System Administrator` |
2022
+ | | | Sourced from Jenkins credential `SONAR_API`. |
2023
+
2024
+
2025
+ ### Sonatype Nexus
2026
+
2027
+ Supported resources are:
2028
+ - Repository
2029
+ - Roles, group mapping and permissions, at repository level or global level
2030
+
2031
+ Repository configuration must follow the `[/#admin/system/api](http://localhost:8681/#admin/system/api)` of your Nexus instance of:
2032
+ - `POST /vi/repositories/docker/hosted`
2033
+ - `POST /vi/repositories/maven/hosted`
2034
+ - ...
2035
+ By default, repository mode is `hosted` and can be overridden with `mode` property.
2036
+
2037
+
2038
+ #### Configuration
2039
+
2040
+ | Parameter | Environment variable | Note | Default |
2041
+ | ------------------ | -------------------- | -------------------------------------------- | ------- |
2042
+ | `--nexus-endpoint` | `NEXUS_ENDPOINT` | HTTPS endpoint | |
2043
+ | | | Sourced from Jenkins build parameter. | |
2044
+ | `--nexus-user` | `NEXUS_USER` | LDAP or internal user name | `admin` |
2045
+ | | | Sourced from Jenkins credential `NEXUS_API`. | |
2046
+ | `--nexus-password` | `NEXUS_PASSWORD` | LDAP or internal password | |
2047
+ | | | Sourced from Jenkins credential `NEXUS_API`. | |
2048
+
2049
+
2050
+ ### Harbor
2051
+
2052
+ Supported resources are:
2053
+ - Projects
2054
+ - Roles and group mapping, at project level
2055
+
2056
+
2057
+ #### Configuration
2058
+
2059
+ | Parameter | Environment variable | Note | Default |
2060
+ | ------------------- | -------------------- | --------------------------------------------- | ------- |
2061
+ | `--harbor-endpoint` | `HARBOR_ENDPOINT` | HTTPS endpoint | |
2062
+ | | | Sourced from Jenkins build parameter. | |
2063
+ | `--harbor-user` | `HARBOR_USER` | LDAP or internal user name | `admin` |
2064
+ | | | Sourced from Jenkins credential `HARBOR_API`. | |
2065
+ | `--harbor-password` | `HARBOR_PASSWORD` | LDAP or internal password | |
2066
+ | | | Sourced from Jenkins credential `HARBOR_API`. | |
2067
+
2068
+
2069
+ ### GitLab
2070
+
2071
+ No resources are supported, only roles. GitLab groups and sub-groups are created according to the given groups and naming guidelines.
2072
+ Real Git repository projects are not managed by this CLI.
2073
+
2074
+ #### Configuration
2075
+
2076
+ | Parameter | Environment variable | Note | Default |
2077
+ | ---------------------------------- | -------------------------------- | ------------------------------------------------------------------- | -------- |
2078
+ | `--gitlab-endpoint` | `GITLAB_ENDPOINT` | HTTPS endpoint | |
2079
+ | | | Sourced from Jenkins global `GITLAB_ENDPOINT` environment variable. | |
2080
+ | `--gitlab-token` | `GITLAB_TOKEN` | Access token with following constraints: | |
2081
+ | | | - Type: `Personal or Group Access Token` | |
2082
+ | | | - Scope is `${gitlab_base_group}` or root level | |
2083
+ | | | - Role: `owner` role | |
2084
+ | | | - Access level: `api` | |
2085
+ | | | Sourced from Jenkins credential `GITLAB_API`. | |
2086
+ | `--gitlab-base-group` | `GITLAB_BASE_GROUP` | Base group where created groups sit | `/` |
2087
+ | `--gitlab-wrapper-group` | `GITLAB_WRAPPER_GROUP` | Path of created wrapper group. Ignored if undefined | `ligoj` |
2088
+ | `--gitlab-wrapper-group-name` | `GITLAB_WRAPPER_GROUP_NAME` | Name of created wrapper group | |
2089
+ | `--gitlab_project_subgroup_prefix` | `GITLAB_PROJECT_SUBGROUP_PREFIX` | Path prefix of created groups. No wrapper if undefined | `ligoj-` |
2090
+
2091
+
2092
+ #### Created hierarchy
2093
+
2094
+ Project hierarchy for a project `project1`:
2095
+
2096
+ | Gitlab path | Path pattern | Default |
2097
+ | -------------------------------------------------------------------- | ---------------------------------------------------------- | --------------- |
2098
+ | /base | `${gitlab_base_group}` | `/` |
2099
+ | &vert;_ project1 | `${gitlab_project_group_prefix}${project_key}` | *No prefix* |
2100
+ | &nbsp;&nbsp;&nbsp;&vert;&mdash; any-repo | *Git repository, not managed* | |
2101
+ | &nbsp;&nbsp;&nbsp;&vert;&mdash; any-group | *User group, not managed* | |
2102
+ | &nbsp;&nbsp;&nbsp;&vert;_ ligoj | `${gitlab_wrapper_group}` | `ligoj` |
2103
+ | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&vert;_ ligoj-project1-dev | `${gitlab-project-subgroup-prefix}${project_key}-${group}` | Prefix `ligoj-` |
2104
+
2105
+ Sub-groups are created with `project_creation_level` flag set to `noone` and with a specific avatar. See [GitLab API create-a-subgroup](https://docs.gitlab.com/ee/api/groups.html#create-a-subgroup)
2106
+
2107
+
2108
+ ### ArgoCD
2109
+
2110
+ Supported resources are:
2111
+ - Projects
2112
+ - Roles and permissions, at project level only
2113
+ - `action: [delete, get]`
2114
+ - `permission: [allow,deny]`, by default `allow`
2115
+ - `application:`, by default `*`
2116
+
2117
+ Sample JSON part:
2118
+
2119
+ ```json
2120
+ {
2121
+ "projects": [
2122
+ {
2123
+ "name": "project1",
2124
+ "description": "Project description",
2125
+ "roles": {
2126
+ "dev": {
2127
+ "permissions": [
2128
+ {
2129
+ "action": "get"
2130
+ },
2131
+ {
2132
+ "action": "delete",
2133
+ "application": "app1",
2134
+ "permission": "deny"
2135
+ }
2136
+ ]
2137
+ },
2138
+ "test": {
2139
+ "permissions": [
2140
+ {
2141
+ "action": "get"
2142
+ }
2143
+ ]
2144
+ }
2145
+ }
2146
+ }
2147
+ ]
2148
+ }
2149
+ ```
2150
+
2151
+ #### Configuration
2152
+
2153
+ | Parameter | Environment variable | Note |
2154
+ | ------------------- | -------------------- | -------------------------------------------------------- |
2155
+ | `--argocd-endpoint` | `ARGOCD_ENDPOINT` | HTTPS endpoint. |
2156
+ | | | Sourced from Jenkins build parameter. |
2157
+ | `--argocd-user` | `ARGOCD_USER` | Username. Not recommended, see `ARGOCD_TICKET` |
2158
+ | `--argocd-password` | `ARGOCD_PASSWORD` | Password. Not recommended, see `ARGOCD_TICKET` |
2159
+ | `--argocd-ticket` | `ARGOCD_TICKET` | Ticket generated by `/alfresco/s/api/login` API |
2160
+ | | | Generated automatically if `ARGOCD_PASSWORD` is provided |
2161
+ | | | Sourced from Jenkins credential `ARGOCD_API`. |
2162
+
2163
+
2164
+ ### Alfresco
2165
+
2166
+ Supported resources are:
2167
+ - Sites
2168
+ - Roles and permissions, at site level only
2169
+
2170
+ ```bash
2171
+ ligoj bootstrap create-roles --schema='{
2172
+ "properties": {
2173
+ "groups": {
2174
+ "items": {
2175
+ "enum": [
2176
+ "dev",
2177
+ "admin",
2178
+ "test",
2179
+ "securite"
2180
+ ]
2181
+ }
2182
+ },
2183
+ "alfresco": {
2184
+ "properties": {
2185
+ "sites": {
2186
+ "maxItems": 1
2187
+ }
2188
+ }
2189
+ }
2190
+ }
2191
+ }' --project "project1" --group-suffix="-team" --from="conf/sample.conf.alfresco.json"
2192
+ ```
2193
+
2194
+
2195
+ #### Configuration
2196
+
2197
+ | Parameter | Environment variable | Note |
2198
+ | --------------------- | -------------------- | --------------------------------------------------------------------- |
2199
+ | `--alfresco-endpoint` | `ALFRESCO_ENDPOINT` | HTTPS endpoint. |
2200
+ | | | Sourced from Jenkins global `ALFRESCO_ENDPOINT` environment variable. |
2201
+ | `--alfresco-user` | `ALFRESCO_USER` | Username. Not recommended, see `ALFRESCO_TICKET` |
2202
+ | `--alfresco-password` | `ALFRESCO_PASSWORD` | Password. Not recommended, see `ALFRESCO_TICKET` |
2203
+ | `--alfresco-ticket` | `ALFRESCO_TICKET` | Ticket generated by `/alfresco/s/api/login` API |
2204
+ | | | Generated automatically if `ALFRESCO_PASSWORD` is provided |
2205
+ | | | Sourced from Jenkins credential `ALFRESCO_API`. |
2206
+
2207
+ Alfresco ticket generation by API:
2208
+ - either from Swagger API explorer `/?urls.primaryName=Authentication%20API#/authentication/createTicket`,
2209
+ - either with cURL command:
2210
+ ```bash
2211
+ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' "https://alfresco.sample.com/alfresco/s/api/login"
2212
+ ```
2213
+
2214
+ ## Bootstrap delete-roles
2215
+
2216
+ Delete mapped roles from various tools symmetrically as [`create-roles` operation](#bootstrap-create-roles).
2217
+
2218
+ ![Sequence](docs/bootstrap/delete-roles.png)
2219
+
2220
+
2221
+ See [`--from`](#--from) for JSON loading options
2222
+
2223
+ By default, only roles are deleted; to perform a full cleanup, see the [--with-data option](#--with-data)
2224
+
2225
+ ```bash
2226
+ ligoj bootstrap delete-roles --project project-a --from conf.json \
2227
+ --with-data "jenkins" "sonar" \
2228
+ --argocd-token="$ARGOCD_TOKEN" \
2229
+ --argocd-user="$ARGOCD_USER" \
2230
+ --alfresco-endpoint="$ALFRESCO_ENDPOINT" \
2231
+ --alfresco-user="$ALFRESCO_USER" \
2232
+ --alfresco-password="$ALFRESCO_PASSWORD" \
2233
+ --nexus-endpoint="$NEXUS_ENDPOINT" \
2234
+ --nexus-user="$NEXUS_USER" \
2235
+ --nexus-password="$NEXUS_PASSWORD" \
2236
+ --gitlab-endpoint="$GITLAB_ENDPOINT" \
2237
+ --gitlab-token="$GITLAB_TOKEN" \
2238
+ --jenkins-home="$JENKINS_HOME" \
2239
+ --jenkins-endpoint="$JENKINS_ENDPOINT" \
2240
+ --sonar-endpoint="$SONAR_ENDPOINT" \
2241
+ --sonar-api-token="$SONAR_API_KEY" \
2242
+ ```
2243
+
2244
+ Deleted contents by tools
2245
+
2246
+ | Tool | Content type | Deletion mode | Only `with-data` |
2247
+ | -------------- | ----------------------- | ------------- | ---------------- |
2248
+ | Jenkins | Folder RBAC Permissions | One by one | |
2249
+ | Jenkins | Global RBAC Permissions | One by one | |
2250
+ | Jenkins | Folder credentials | One by one | ✅ |
2251
+ | Jenkins | Global credentials | One by one | ✅ |
2252
+ | Jenkins | Folders | One by one | ✅ |
2253
+ | SonarQube | Groups and RBAC | One by one | |
2254
+ | SonarQube | Projects | One by one | ✅ |
2255
+ | SonarQube | Templates | One by one | ✅ |
2256
+ | GitLab | Wrapper project Groups | Cascade | |
2257
+ | GitLab | LDAP project Groups | One by one | |
2258
+ | GitLab | Project Groups | One by one | ✅ |
2259
+ | Sonatype Nexus | Roles | Cascade | |
2260
+ | Sonatype Nexus | Repositories | One by one | ✅ |
2261
+ | Alfresco | Roles | Cascade | |
2262
+ | Alfresco | Sites | One by one | ✅ |
2263
+ | ArgoCD | Permissions | One by one | |
2264
+ | ArgoCD | Projects | One by one | ✅ |
2265
+
2266
+
2267
+ ### `--with-data`
2268
+
2269
+ Each supported tool can be included (by default) or excluded, as described in [`create-roles` includes/excludes option documentation](#--includes-and---excludes-options). For excluded tools, no role and no data are deleted.
2270
+
2271
+ By default, only roles are deleted. To symmetrically delete the created contents, `--with-data` must be set to `*` or a specific list of plugins.
2272
+ In this case, all discovered JSON content is considered for deletion, including Jenkins folders, Nexus repositories, etc.
2273
+ - By default, no data is deleted
2274
+ - When `--with-data` is set to `*`, all discovered JSON's content for included plugins is considered
2275
+ - When `--with-data` is set to `plugin1 plugin2`, only these plugins are considered for data deletion, only if these plugins are included
2276
+
2277
+ ## Bootstrap roundtrip
2278
+
2279
+ The purpose of this documentation is only for troubleshooting and understanding the full behavior of bootstrap operations:
2280
+ - [Bootstrap init](#bootstrap-init) : initial IDP (LDAP, ...), administrative setup. Only executed once.
2281
+ - [Bootstrap welcome-user](#bootstrap-welcome-user): initial administration user. Each administrator can execute their own base configuration.
2282
+ - [Bootstrap create-project](#bootstrap-create-project): create a new project in Ligoj and the linked IDP
2283
+ - [Bootstrap create-roles](#bootstrap-create-roles): permissions, role mapping and containers creation for an existing project
2284
+ - [Bootstrap delete-roles](#bootstrap-delete-roles): permissions, role mapping and containers deletion from a project
2285
+ - [Bootstrap delete-project](#bootstrap-delete-project): delete a project from Ligoj and linked IDP
2286
+
2287
+ Commands from zero to zero:
2288
+
2289
+ ```bash
2290
+ ligoj -V bootstrap init --base-dn="dc=sample,dc=com"
2291
+ ligoj -V bootstrap welcome-user --id "jdupont" --project "pic-master" --name "PIC Master" --script-custom-attributes '{"uidFonctionnel":"pic-master-script"}' --reader-custom-attributes '{"uidFonctionnel":"pic-master-reader"}' --jenkins-create-node --sonar-create-node --reset-reader-password
2292
+ ligoj -V bootstrap create-project --project "project-module1" --name "ProjetNew" --groups "dev" "admin" --parent-project "pic-master" --parent-admin "jdupont" --team-leader jdupont
2293
+ ligoj -V bootstrap create-roles --project "project-module1" --from "conf/ligoj/sample.conf.json" --excludes gitlab alfresco argocd
2294
+ ligoj -V bootstrap create-roles --project "project-module1" --from "conf/ligoj/sample.conf.json" --excludes gitlab
2295
+ ligoj -V bootstrap delete-roles --project "project-module1" --from "conf/ligoj/sample.conf.json" --excludes gitlab
2296
+ ligoj -V project delete --id "project-module1" --parent-admin "jdupont" --with-data '*'
2297
+ ligoj -V project delete --id "pic-master" --with-data '*'
2298
+ ```
2299
+
2300
+ # Ligoj SSL Certificates
2301
+
2302
+ This section covers the case of running Ligoj with interaction with HTTPS services using self-signed certificates or issued by internal Certificate Authorities.
2303
+
2304
+ For each HTTPS website, run the following command. It requires `keytool` to be available on the host.
2305
+
2306
+ ```bash
2307
+ python plugins/ssl.py keycloack.sample.com 443 ./ligoj.jks changeit
2308
+ ```
2309
+
2310
+ When successive calls are done, the target TrustStore JKS file contains all aggregated certificates and can be provided to `ligoj-ui` and/or `ligoj-api` containers.
2311
+
2312
+ ```bash
2313
+ # Copy the TrustStore file in the mounted Ligoj home directory
2314
+ cp ./ligoj.jks /var/lib/instance_datas/ligoj/
2315
+
2316
+ # Start the container with the TrustStore reference
2317
+ docker run -e CUSTOM_OPTS='-Djavax.net.ssl.trustStore=/home/ligoj/ligoj.jks' \
2318
+ ```
2319
+
2320
+
2321
+ # Development mode installation
2322
+
2323
+ This procedure is only for development where Ligoj CLI package is installed in *editable*.
2324
+
2325
+ ```bash
2326
+ echo '
2327
+ export PYENV_ROOT="$HOME/.pyenv"
2328
+ command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
2329
+ eval "$(pyenv init -)"' >> ~/.bashrc
2330
+ source ~/.bashrc
2331
+ brew install pyenv-virtualenv 3.11 ligoj # See https://github.com/pyenv/pyenv-virtualenv
2332
+ pyenv install 3.11
2333
+ pyenv virtualenv 3.11 ligoj
2334
+ pyenv activate ligoj
2335
+
2336
+ # Proxy configuration
2337
+ export PYTHON_OPTS=' --proxy="10.154.154.154:3128"'
2338
+ export http_proxy="http://10.154.154.154:3128"
2339
+ export https_proxy="http://10.154.154.154:3128"
2340
+ export NO_PROXY="localhost,*.rie.gouv.fr,127.0.0.1,0.0.0.0,ligoj.$TENANT"
2341
+
2342
+ pip install --upgrade pip
2343
+ pip install -U --root-user-action=ignore pip -e .
2344
+
2345
+ # Build
2346
+ python -m pip install --upgrade build
2347
+ python -m build
2348
+ ruff check . --fix
2349
+ flake8 .
2350
+ ```