-
Notifications
You must be signed in to change notification settings - Fork 115
/
main.yml
989 lines (864 loc) · 52.9 KB
/
main.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
- set_fact:
k8s_plugin: kubernetes.core.k8s
- name: Get the original CR as-is for the camelCase keys and so we can update its status field
set_fact:
current_cr: "{{ _kiali_io_kiali }}"
- include_tasks: update-status-progress.yml
vars:
status_progress_message: "Initializing"
status_vars:
specVersion: "{{ kiali_vars.version }}"
deployment:
accessibleNamespaces: null
- name: Get api group information from the cluster
set_fact:
api_groups: "{{ lookup(k8s_plugin, cluster_info='api_groups') }}"
when:
- is_openshift == False
- is_k8s == False
- name: Get api version information from the cluster
k8s_cluster_info:
register: api_status
- name: Determine the cluster type
set_fact:
is_openshift: "{{ True if 'route.openshift.io' in api_groups else False }}"
is_k8s: "{{ False if 'route.openshift.io' in api_groups else True }}"
when:
- is_openshift == False
- is_k8s == False
# Indicate what kind of cluster we are in (OpenShift or Kubernetes).
- debug:
msg: "CLUSTER TYPE: is_openshift={{ is_openshift }}; is_k8s={{ is_k8s }}"
- fail:
msg: "Cannot determine what type of cluster we are in"
when:
- is_openshift == False
- is_k8s == False
- name: Determine the Kubernetes version
set_fact:
k8s_version: "{{ lookup(k8s_plugin, cluster_info='version').kubernetes.gitVersion | regex_replace('^v', '') }}"
ignore_errors: yes
- name: Determine the OpenShift version
vars:
kube_apiserver_cluster_op_raw: "{{ lookup(k8s_plugin, api_version='config.openshift.io/v1', kind='ClusterOperator', resource_name='kube-apiserver') | default({}) }}"
ri_query: "status.versions[?name == 'raw-internal'].version"
set_fact:
openshift_version: "{{ kube_apiserver_cluster_op_raw | json_query(ri_query) | join }}"
when:
- is_openshift == True
- name: Determine the Istio implementation
set_fact:
is_maistra: "{{ True if 'maistra.io' in api_groups else False }}"
- name: Get information about the operator
k8s_info:
api_version: v1
kind: Pod
namespace: "{{ lookup('env', 'POD_NAMESPACE') }}"
name: "{{ lookup('env', 'POD_NAME') }}"
register: operator_pod_raw
ignore_errors: yes
- name: Determine the version of the operator based on the version label
set_fact:
operator_version: "{{ operator_pod_raw.resources[0].metadata.labels.version }}"
when:
- operator_pod_raw is defined
- operator_pod_raw.resources[0] is defined
- operator_pod_raw.resources[0].metadata is defined
- operator_pod_raw.resources[0].metadata.labels is defined
- operator_pod_raw.resources[0].metadata.labels.version is defined
- set_fact:
operator_version: "unknown"
when:
- operator_version is not defined
- debug:
msg: "OPERATOR VERSION: [{{ operator_version }}]"
# To remain backward compatible with some settings that have changed in later releases,
# let's take some deprecated settings and set the current settings appropriately.
- name: deployment.ingress_enabled is deprecated but if deployment.ingress.enabled is not set then use the old setting
set_fact:
kiali_vars: |
{% set ie=kiali_vars['deployment'].pop('ingress_enabled') %}
{{ kiali_vars | combine({'deployment': {'ingress': {'enabled': ie|bool }}}, recursive=True) }}
when:
- kiali_vars.deployment.ingress_enabled is defined
- kiali_vars.deployment.ingress is not defined or kiali_vars.deployment.ingress.enabled is not defined
- name: api.namespaces.label_selector is deprecated but if api.namespaces.label_selector_include is not set then use the old setting
set_fact:
kiali_vars: |
{% set ls=kiali_vars['api']['namespaces'].pop('label_selector') %}
{{ kiali_vars | combine({'api': {'namespaces': {'label_selector_include': ls|bool }}}, recursive=True) }}
when:
- kiali_vars.api.namespaces.label_selector is defined
- kiali_vars.api.namespaces.label_selector_include is not defined
# convert snake case to camelCase where appropriate
- include_tasks: snake_camel_case.yaml
- name: Print some debug information
vars:
msg: |
Kiali Variables:
--------------------------------
{{ kiali_vars | to_nice_yaml }}
debug:
msg: "{{ msg.split('\n') }}"
- name: Set default deployment namespace to the same namespace where the CR lives
set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'namespace': current_cr.metadata.namespace}}, recursive=True) }}"
when:
- kiali_vars.deployment.namespace is not defined or kiali_vars.deployment.namespace == ""
# Never allow the deployment.instance_name or deployment.namespace to change to avoid leaking resources - to uninstall resources you must delete the Kiali CR
- name: Ensure the deployment.instance_name has not changed
fail:
msg: "The deployment.instance_name cannot be changed to a different value. It was [{{ current_cr.status.deployment.instanceName }}] but is now [{{ kiali_vars.deployment.instance_name }}]. In order to install Kiali with a different deployment.instance_name, please uninstall Kiali first."
when:
- current_cr.status is defined
- current_cr.status.deployment is defined
- current_cr.status.deployment.instanceName is defined
- current_cr.status.deployment.instanceName != kiali_vars.deployment.instance_name
- name: Ensure the deployment.namespace has not changed
fail:
msg: "The deployment.namespace cannot be changed to a different value. It was [{{ current_cr.status.deployment.namespace }}] but is now [{{ kiali_vars.deployment.namespace }}]. In order to install Kiali with a different deployment.namespace, please uninstall Kiali first."
when:
- current_cr.status is defined
- current_cr.status.deployment is defined
- current_cr.status.deployment.namespace is defined
- current_cr.status.deployment.namespace != kiali_vars.deployment.namespace
- name: Only allow ad-hoc kiali namespace when appropriate
fail:
msg: "The operator is forbidden from installing Kiali in a namespace [{{ kiali_vars.deployment.namespace }}] that is different from the namespace where the CR was created [{{ current_cr.metadata.namespace }}]"
when:
- kiali_vars.deployment.namespace != current_cr.metadata.namespace
- lookup('env', 'ALLOW_AD_HOC_KIALI_NAMESPACE') | default('false', True) != "true"
- name: Make sure instance_name follows the DNS label standard because it will be a Service name
fail:
msg: "The value for deployment.instance_name [{{ kiali_vars.deployment.instance_name }}] does not follow the DNS label standard as defined in RFC 1123. In short, it must only contain lowercase alphanumeric characters or '-'."
when:
# regex must follow https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
# restrict to 40 chars, not 63, because instance_name is a prefix and we need to prepend additional chars for some resource names (like "-service-account")
- kiali_vars.deployment.instance_name is not regex('^(?![0-9]+$)(?!-)[a-z0-9-]{,40}(?<!-)$')
- name: "Determine environment to store in status"
set_fact:
status_environment: "{{ status_environment | default({}) | combine({item.0: item.1}) }}"
loop: "{{ data[0] | zip(data[1]) | list }}"
vars:
data:
- ['isKubernetes', 'isOpenshift', 'isMaistra', 'kubernetesVersion', 'openshiftVersion', 'operatorVersion']
- ["{{is_k8s}}", "{{is_openshift}}", "{{is_maistra}}", "{{k8s_version|default('')}}", "{{openshift_version|default('')}}", "{{operator_version}}"]
when:
- item.1 != ""
- item.1 != "false"
- item.1 != False
- include_tasks: update-status-progress.yml
vars:
status_progress_message: "Setting up configuration"
status_vars:
environment: "{{ status_environment | default({}) }}"
deployment:
instanceName: "{{ kiali_vars.deployment.instance_name }}"
namespace: "{{ kiali_vars.deployment.namespace }}"
- name: Validate web_schema configuration
fail:
msg: "Invalid server.web_schema [{{ kiali_vars.server.web_schema }}]! Must be empty, or one of either 'http' or 'https'"
when:
- kiali_vars.server.web_schema != ''
- kiali_vars.server.web_schema != 'https'
- kiali_vars.server.web_schema != 'http'
- name: Validate web_history_mode configuration
fail:
msg: "Invalid server.web_history_mode [{{ kiali_vars.server.web_history_mode }}]! Must be empty, or one of either 'browser' or 'hash'"
when:
- kiali_vars.server.web_history_mode != ''
- kiali_vars.server.web_history_mode != 'browser'
- kiali_vars.server.web_history_mode != 'hash'
- name: Only allow ad-hoc kiali image when appropriate
fail:
msg: "The operator is forbidden from accepting a Kiali CR that defines an ad hoc Kiali image [{{ kiali_vars.deployment.image_name }}{{ '@' + kiali_vars.deployment.image_digest if kiali_vars.deployment.image_digest != '' else '' }}:{{ kiali_vars.deployment.image_version }}]. Remove spec.deployment.image_name, spec.deployment.image_version, and spec.deployment.image_digest from the Kiali CR."
when:
- kiali_vars.deployment.image_name != "" or kiali_vars.deployment.image_version != "" or kiali_vars.deployment.image_digest != ""
- lookup('env', 'ALLOW_AD_HOC_KIALI_IMAGE') | default('false', True) != "true"
# We do not want to blindly default to istio-system for some namespaces. If the istio_namespace is not
# provided, assume it is the same namespace where Kiali is being deployed. Set the other istio namespace
# values accordingly.
# We determine the default Istio namespace var first, and the rest will use it for their default as appropriate.
- name: Set configuration defaults
vars:
resource_limits_default:
requests:
cpu: "10m"
memory: "64Mi"
limits:
memory: "1Gi"
kiali_vars_yaml: |
{# Initialize #}
{% set kv = kiali_vars %}
{# Set default istio namespace #}
{% if kv.istio_namespace == "" %}
{% set kv = kv | combine({'istio_namespace': kv.deployment.namespace}, recursive=True) %}
{% endif %}
{# Set default root namespace #}
{% if kv.external_services.istio.root_namespace == "" %}
{% set kv = kv | combine({'external_services': {'istio': {'root_namespace': kv.istio_namespace}}}, recursive=True) %}
{% endif %}
{# Set default Grafana in_cluster_url #}
{% if kv.external_services.grafana.in_cluster_url is not defined %}
{% set kv = kv | combine({'external_services': {'grafana': {'in_cluster_url': 'http://grafana.' + kv.istio_namespace + ':3000'}}}, recursive=True) %}
{% endif %}
{# Set default Tracing in_cluster_url for Maistra #}
{% if kv.external_services.tracing.in_cluster_url == "" and is_maistra %}
{% set kv = kv | combine({'external_services': {'tracing': {'in_cluster_url': 'http://tracing.' + kv.istio_namespace + ':16686'}}}, recursive=True) %}
{% endif %}
{# Set default Tracing in_cluster_url for grpc consumption #}
{% if is_maistra == False and kv.external_services.tracing.in_cluster_url == "" and (kv.external_services.tracing.use_grpc is not defined or kv.external_services.tracing.use_grpc|bool == True) %}
{% set kv = kv | combine({'external_services': {'tracing': {'in_cluster_url': 'http://tracing.' + kv.istio_namespace + ':16685/jaeger'}}}, recursive=True) %}
{% endif %}
{# Set default Tracing in_cluster_url for http consumption #}
{% if is_maistra == False and kv.external_services.tracing.in_cluster_url == "" and kv.external_services.tracing.use_grpc is defined and kv.external_services.tracing.use_grpc|bool == False %}
{% set kv = kv | combine({'external_services': {'tracing': {'in_cluster_url': 'http://tracing.' + kv.istio_namespace + '/jaeger'}}}, recursive=True) %}
{% endif %}
{# Set default Istio service that provides version info (istiod service that was introduced in Istio 1.6) #}
{% if kv.external_services.istio.url_service_version == "" %}
{% set kv = kv | combine({'external_services': {'istio': {'url_service_version': 'http://' + kv.external_services.istio.istiod_deployment_name + '.' + kv.istio_namespace + ':15014/version'}}}, recursive=True) %}
{% endif %}
{# Set default Prometheus URL #}
{% if kv.external_services.prometheus.url == "" %}
{% set kv = kv | combine({'external_services': {'prometheus': {'url': 'http://prometheus.' + kv.istio_namespace + ':9090'}}}, recursive=True) %}
{% endif %}
{# Set default HPA api_version #}
{% if kv.deployment.hpa.api_version == "" %}
{% set kv = kv | combine({'deployment': {'hpa': {'api_version': 'autoscaling/v2' if (api_status.apis['autoscaling/v2'] is defined) else 'autoscaling/v2beta2' }}}, recursive=True) %}
{% endif %}
{# Provide some default resource limits #}
{% if kv.deployment.resources is not defined %}
{% set kv = kv | combine({'deployment': {'resources': resource_limits_default }}, recursive=True) %}
{% endif %}
{# Set default deployment.ingress.enabled based on cluster type (disable on k8s; enable on OpenShift) #}
{% if kv.deployment.ingress.enabled is not defined or kv.deployment.ingress.enabled == "" %}
{% set kv = kv | combine({'deployment': {'ingress': {'enabled': true if is_openshift else false }}}, recursive=True) %}
{% endif %}
{# Set default tracing use_grpc setting #}
{% if kv.external_services.tracing.use_grpc is not defined %}
{% set kv = kv | combine({'external_services': {'tracing': { 'use_grpc': False if is_maistra else True }}}, recursive=True) %}
{% endif %}
{# Set default web root based on cluster type #}
{% if kv.server.web_root == "" %}
{% set kv = kv | combine({'server': {'web_root': '/' if is_openshift else '/kiali'}}, recursive=True) %}
{% endif %}
{# Make sure web root never ends with a slash #}
{% if kv.server.web_root != "/" and kv.server.web_root is match(".*/$") %}
{% set kv = kv | combine({'server': {'web_root': kv.server.web_root | regex_replace('\\/$', '')}}, recursive=True) %}
{% endif %}
{# Set default identity cert_file based on cluster type (non-OpenShift clusters do not get a default identity) #}
{% if kv.identity.cert_file is not defined %}
{% set kv = kv | combine({'identity': {'cert_file': '/kiali-cert/tls.crt' if is_openshift else ''}}, recursive=True) %}
{% endif %}
{# Set default identity private_key_file based on cluster type (non-OpenShift clusters do not get a default identity) #}
{% if kv.identity.private_key_file is not defined %}
{% set kv = kv | combine({'identity': {'private_key_file': '/kiali-cert/tls.key' if is_openshift else ''}}, recursive=True) %}
{% endif %}
{# Default the image name to a known supported image. #}
{% if kv.deployment.image_name == "" %}
{% set kv = kv | combine({'deployment': {'image_name': supported_kiali_images[kv.version].image_name}}, recursive=True) %}
{% endif %}
{# Default the image version to a known supported image. #}
{% if kv.deployment.image_version == "" %}
{% set kv = kv | combine({'deployment': {'image_version': ('latest' if operator_version == 'master' else operator_version) if supported_kiali_images[kv.version].image_version == 'operator_version' else supported_kiali_images[kv.version].image_version}}, recursive=True) %}
{% endif %}
{# If image version is latest then we will want to always pull #}
{% if kv.deployment.image_version == "latest" %}
{% set kv = kv | combine({'deployment': {'image_pull_policy': 'Always'}}, recursive=True) %}
{% endif %}
{# Set default auth strategy based on cluster type #}
{% if kv.auth.strategy == "" %}
{% set kv = kv | combine({'auth': {'strategy': 'openshift' if is_openshift else 'token'}}, recursive=True) %}
{% endif %}
{# Use OpenShift service CA file for Grafana #}
{% if is_openshift == True and (kv.external_services.grafana.auth.ca_file is not defined or kv.external_services.grafana.auth.ca_file == '') %}
{% set kv = kv | combine({'external_services': {'grafana': {'auth': {'ca_file': '/kiali-cabundle/service-ca.crt'}}}}, recursive=True) %}
{% endif %}
{# Use OpenShift service CA file for Prometheus #}
{% if is_openshift == True and (kv.external_services.prometheus.auth.ca_file is not defined or kv.external_services.prometheus.auth.ca_file == '') %}
{% set kv = kv | combine({'external_services': {'prometheus': {'auth': {'ca_file': '/kiali-cabundle/service-ca.crt'}}}}, recursive=True) %}
{% endif %}
{# Use OpenShift service CA file for Tracing #}
{% if is_openshift == True and (kv.external_services.tracing.auth.ca_file is not defined or kv.external_services.tracing.auth.ca_file == '') %}
{% set kv = kv | combine({'external_services': {'tracing': {'auth': {'ca_file': '/kiali-cabundle/service-ca.crt'}}}}, recursive=True) %}
{% endif %}
{# Make sure the correct auth.openshift.client_id_prefix is defined when using openshift auth strategy #}
{% if kv.auth.strategy == 'openshift' and kv.auth.openshift.client_id_prefix != kv.deployment.instance_name %}
{% set kv = kv | combine({'auth': {'openshift': {'client_id_prefix': kv.deployment.instance_name }}}, recursive=True) %}
{% endif %}
{# The default cluster_wide_access setting is determined by deployment.accessible_namespaces #}
{% if kv.deployment.cluster_wide_access is not defined %}
{% set kv = kv | combine({'deployment': {'cluster_wide_access': ('**' in kv.deployment.accessible_namespaces)}}, recursive=True) %}
{% endif %}
{# Set the yaml to the new kv dict #}
{{ kv | to_nice_yaml }}
set_fact:
kiali_vars: "{{ kiali_vars_yaml | from_yaml }}"
# Indicate how users are to authenticate to Kiali, making sure the strategy is valid.
- debug:
msg: "AUTH STRATEGY={{ kiali_vars.auth.strategy }}"
- name: Confirm auth strategy is valid for OpenShift environments
fail:
msg: "Invalid auth.strategy [{{ kiali_vars.auth.strategy }}]! Must be one of either 'openshift', 'token' or 'anonymous'"
when:
- is_openshift == True
- kiali_vars.auth.strategy != 'anonymous'
- kiali_vars.auth.strategy != 'openshift'
- kiali_vars.auth.strategy != 'token'
- name: Confirm auth strategy is valid for Kubernetes environments
fail:
msg: "Invalid auth.strategy [{{ kiali_vars.auth.strategy }}]! Must be one of either 'token', 'openid', 'anonymous', or 'header'"
when:
- is_k8s == True
- kiali_vars.auth.strategy != 'anonymous'
- kiali_vars.auth.strategy != 'token'
- kiali_vars.auth.strategy != 'openid'
- kiali_vars.auth.strategy != 'header'
- name: Confirm OpenID configuration when auth strategy is 'openid'
fail:
msg: "Invalid configuration for OpenID connect! The mandatory parameters should be provided: 'issuer_uri', 'client_id'. Also, the 'username_claim' cannot be set to the empty string."
when:
- kiali_vars.auth.strategy == "openid"
- kiali_vars.auth.openid.issuer_uri == "" or kiali_vars.auth.openid.client_id == "" or kiali_vars.auth.openid.username_claim == ""
- name: Check valid value for api_token on OpenID configuration
fail:
msg: "Invalid configuration for OpenID connect! The api_token must be either 'id_token' or 'access_token'"
when:
- kiali_vars.auth.strategy == "openid"
- kiali_vars.auth.openid.api_token != "id_token"
- kiali_vars.auth.openid.api_token != "access_token"
# Fail if ingress is disabled but auth_strategy is openshift. This is because the openshift auth strategy
# requires OAuth Client which requires a Route. So ingress must be enabled if strategy is openshift.
- name: Ensure Ingress is Enabled if Auth Strategy is openshift
fail:
msg: "The auth.strategy is 'openshift' which requires a Route, but deployment.ingress.enabled is false. Aborting."
when:
- kiali_vars.auth.strategy == "openshift"
- kiali_vars.deployment.ingress.enabled|bool == False
- name: Confirm the cluster can access github.com when it needs to determine the last release of Kiali
uri:
url: https://api.github.com/repos/kiali/kiali-operator/releases
when:
- kiali_vars.deployment.image_version == "lastrelease"
- name: Determine image version when last release is to be installed
shell: echo -n $(curl -s https://api.github.com/repos/kiali/kiali-operator/releases 2> /dev/null | grep "tag_name" | sed -e 's/.*://' -e 's/ *"//' -e 's/",//' | grep -v "snapshot" | sort -t "." -k 1.2g,1 -k 2g,2 -k 3g | tail -n 1)
register: github_lastrelease
when:
- kiali_vars.deployment.image_version == "lastrelease"
- set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'image_version': github_lastrelease.stdout}}, recursive=True) }}"
when:
- kiali_vars.deployment.image_version == "lastrelease"
- name: Determine image version when it explicitly was configured as the operator_version
set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'image_version': 'latest' if operator_version == 'master' else operator_version}}, recursive=True) }}"
when:
- kiali_vars.deployment.image_version == "operator_version"
- fail:
msg: "Could not determine what the image version should be. Set deployment.image_version to a valid value"
when:
- kiali_vars.deployment.image_version == "" or kiali_vars.deployment.image_version == "unknown"
- name: Determine version_label based on image_version
set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'version_label': 'master' if kiali_vars.deployment.image_version == 'latest' else kiali_vars.deployment.image_version}}, recursive=True) }}"
when:
- kiali_vars.deployment.version_label == ""
# Kubernetes limits the length of version label strings to 63 characters or less - make sure the label is valid.
- name: Trim version_label when appropriate
set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'version_label': kiali_vars.deployment.version_label[:60] + 'XXX' }}, recursive=True) }}"
when:
- kiali_vars.deployment.version_label | length > 63
# Indicate which Kiali image we are going to use.
- debug:
msg: "IMAGE_NAME={{ kiali_vars.deployment.image_name }}; IMAGE VERSION={{ kiali_vars.deployment.image_version }}; VERSION LABEL={{ kiali_vars.deployment.version_label }}"
- name: Determine what metadata labels to apply to all created resources
set_fact:
kiali_resource_metadata_labels:
app: kiali
version: "{{ kiali_vars.deployment.version_label }}"
app.kubernetes.io/name: kiali
app.kubernetes.io/version: "{{ kiali_vars.deployment.version_label }}"
app.kubernetes.io/instance: "{{ kiali_vars.deployment.instance_name }}"
app.kubernetes.io/part-of: kiali
# Determine the accessible namespaces. The user may have specified names using regex expressions.
# We need to get a list of all namespaces and match them to the regex expressions.
# Note that we replace kiali_vars.deployment.accessible_namespaces with the full list of actual namespace names
# with regex expressions removed because when the CR changes, we need to know what namespaces were granted roles in
# case we need to revoke those roles (to do this, we need to know the exact names of the namespaces).
# This must be done before the next step which is figuring out what namespaces are no longer accessible and revoking their roles.
# If the user did not specify Kiali's own namespace in accessible_namespaces, it will be added to the list automatically.
# NOTE: there is a special value of accessible_namespaces - two asterisks ("**") means Kiali is to be given access to all
# namespaces via a single cluster role (as opposed to individual roles in each accessible namespace).
# Note that we look at deployment.cluster_wide_access to see if ClusterRoles are to be created or not.
# If deployment.cluster_wide_access is False then we create individual Roles per namespace.
# if accessible_namespaces is "**", we must have cluster-wide-access, it is an error otherwise.
- name: Make sure cluster_wide_access does not erroneously restrict access when all namespaces are to be accessible.
fail:
msg: "deployment.cluster_wide_access must be enabled (i.e. 'true') when all namespaces are to be accessible (e.g. deployment.accessible_namespaces is undefined or has '**'). Aborting."
when:
- '"**" in kiali_vars.deployment.accessible_namespaces'
- kiali_vars.deployment.cluster_wide_access == False
# At this point, deployment.cluster_wide_access should now be the source of truth when determining if ClusterRoles or Roles are to be managed.
- name: Determine the Role and RoleBinding kinds that the operator will create and that the role templates will use
set_fact:
role_kind: "{{ 'ClusterRole' if kiali_vars.deployment.cluster_wide_access == True else 'Role' }}"
role_binding_kind: "{{ 'ClusterRoleBinding' if kiali_vars.deployment.cluster_wide_access == True else 'RoleBinding' }}"
- name: Determine if the operator can support cluster wide access - can_i create clusterroles
register: can_i_create_clusterroles
ignore_errors: yes
k8s:
state: present
definition:
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
spec:
resourceAttributes:
group: rbac.authorization.k8s.io
resource: clusterroles
verb: create
when:
- kiali_vars.deployment.cluster_wide_access == True
- name: Determine if the operator can support cluster wide access - can_i create clusterrolebindings
register: can_i_create_clusterrolebindings
ignore_errors: yes
k8s:
state: present
definition:
apiVersion: authorization.k8s.io/v1
kind: SelfSubjectAccessReview
spec:
resourceAttributes:
group: rbac.authorization.k8s.io
resource: clusterrolebindings
verb: create
when:
- kiali_vars.deployment.cluster_wide_access == True
- fail:
msg: "The operator cannot support deployment.accessible_namespaces being unset (or have '**') or cluster_wide_access set to 'true' because it does not have permissions to create ClusterRoles"
when:
- kiali_vars.deployment.cluster_wide_access == True
- can_i_create_clusterroles is defined
- can_i_create_clusterroles.result is defined
- can_i_create_clusterroles.result.status is defined
- can_i_create_clusterroles.result.status.allowed is defined
- can_i_create_clusterroles.result.status.allowed == False
- fail:
msg: "The operator cannot support deployment.accessible_namespaces being unset (or have '**') or cluster_wide_access set to 'true' because it does not have permissions to create ClusterRoleBindings"
when:
- kiali_vars.deployment.cluster_wide_access == True
- can_i_create_clusterrolebindings is defined
- can_i_create_clusterrolebindings.result is defined
- can_i_create_clusterrolebindings.result.status is defined
- can_i_create_clusterrolebindings.result.status.allowed is defined
- can_i_create_clusterrolebindings.result.status.allowed == False
- name: Find all namespaces (this is limited to what the operator has permission to see)
set_fact:
all_namespaces: "{{ lookup(k8s_plugin, api_version='v1', kind='Namespace') | default({}) | json_query('[].metadata.name') }}"
- name: Determine all accessible namespaces, expanding regex expressions to matched namespaces
set_fact:
all_accessible_namespaces: "{{ (all_namespaces | only_accessible_namespaces(accessible_namespaces=kiali_vars.deployment.accessible_namespaces) + [ kiali_vars.deployment.namespace, kiali_vars.istio_namespace, kiali_vars.external_services.istio.root_namespace ]) | unique | sort }}"
when:
- '"**" not in kiali_vars.deployment.accessible_namespaces'
- name: If accessible namespaces list has the special all-namespaces indicator, remove all other namespaces from the list
set_fact:
all_accessible_namespaces: ["**"]
when:
- '"**" in kiali_vars.deployment.accessible_namespaces'
- name: Set deployment.accessible_namespaces to a list of full namespace names
set_fact:
kiali_vars: "{{ kiali_vars | combine({'deployment': {'accessible_namespaces': all_accessible_namespaces }}, recursive=True) }}"
- name: Listing of all accessible namespaces (includes regex matches)
debug:
msg: "{{ kiali_vars.deployment.accessible_namespaces }}"
# do some security checks - abort if the operator is forbidden from allowing certain accessible_namespace values
- name: Abort if all namespace access is not allowed
fail:
msg: "The operator is forbidden from installing Kiali with deployment.accessible_namespaces unset (or have '**') or deployment.cluster_wide_access set to 'true'"
when:
- kiali_vars.deployment.cluster_wide_access == True
- lookup('env', 'ALLOW_ALL_ACCESSIBLE_NAMESPACES') | default('false', True) != "true"
- name: Get labeled accessible namespaces
vars:
label: "{{ lookup('env', 'ACCESSIBLE_NAMESPACES_LABEL') | default('', True) }}"
label_selector: "{{ label + ('' if label is regex('^.+=.+$') else ('=' + kiali_vars.istio_namespace)) }}"
set_fact:
only_allowed_labeled_namespaces: "{{ query(k8s_plugin, kind='Namespace', api_version='v1', label_selector=label_selector) | json_query('[*].metadata.name') }}"
when:
- kiali_vars.deployment.cluster_wide_access == False
- label != ""
- name: Abort if accessible namespaces contains namespaces not labeled
vars:
ns_diff: "{{ kiali_vars.deployment.accessible_namespaces | difference(only_allowed_labeled_namespaces) }}"
fail:
msg: "Operator is forbidden to allow Kiali CR to specify one or more accessible namespaces that were not labeled: {{ ('Number of rejected namespaces=' + (ns_diff | length | string)) if (ns_diff | length > 10) else (ns_diff) }}"
when:
- kiali_vars.deployment.cluster_wide_access == False
- only_allowed_labeled_namespaces is defined
- ns_diff | length > 0
# Note that we add the instance name to the member-of key name only if the instance name is not the default 'kiali'.
# This is for backward compatibility, and for simplicity when deploying under normal default conditions.
- name: When accessible namespaces are specified and we are not to give cluster wide access, ensure label_selector_include is set
set_fact:
kiali_vars: "{{ kiali_vars | combine({'api': {'namespaces': {'label_selector_include': ('kiali.io/' + ((kiali_vars.deployment.instance_name + '.') if kiali_vars.deployment.instance_name != 'kiali' else '') + 'member-of=' + kiali_vars.deployment.namespace)}}}, recursive=True) }}"
when:
- kiali_vars.deployment.cluster_wide_access == False
- kiali_vars.api.namespaces.label_selector_include is not defined
- name: Make sure label_selector_include is in the valid format name=value
fail:
msg: "The api.namespaces.label_selector_include is not valid [{{ kiali_vars.api.namespaces.label_selector_include }}] - it must be in the form of 'name=value' following Kubernetes syntax rules for label names and values."
when:
- kiali_vars.api.namespaces.label_selector_include is defined
# this regex is not 100% accurate, but we want to at least catch obvious errors
- kiali_vars.api.namespaces.label_selector_include is not regex('^[a-zA-Z0-9/_.-]+=[a-zA-Z0-9_.-]+$')
# If the signing key is not empty string, and is not of the special value secret:name:key,
# do some validation on it's length
- name: Validate signing key, if it is set in the CR
fail:
msg: "Signing key must be 16, 24 or 32 byte length"
when:
- kiali_vars.auth.strategy != 'anonymous'
- kiali_vars.login_token.signing_key != ""
- not(kiali_vars.login_token.signing_key | regex_search('secret:.+:.+'))
- kiali_vars.login_token.signing_key | length != 16
- kiali_vars.login_token.signing_key | length != 24
- kiali_vars.login_token.signing_key | length != 32
# If the signing key is empty string, we need to ensure a signing key secret exists. If one does not exist, we need to generate one.
# Note that to avoid granting to the operator the very powerful permission to CRUD all secrets in all namespaces, we always generate
# a signing key secret with the name "kiali-signing-key" regardless of the value of kiali_vars.deployment.instance_name.
# Thus, all Kiali instances will be using the same signing key secret name. If the user does not want this, they can generate their
# own secret with their own key (which is a smart thing to do anyway). The user tells the operator what the name of that secret
# signing key is via "login_token.signing_key" with value "secret:<theSecretName>:<theSecretKey>".
- name: Get information about any existing signing key secret if we need to know if it exists or not
k8s_info:
api_version: v1
kind: Secret
namespace: "{{ kiali_vars.deployment.namespace }}"
name: kiali-signing-key
register: signing_key_secret_raw
when:
- kiali_vars.login_token.signing_key == ""
- name: Create kiali-signing-key secret to store a random signing key if a secret does not already exist and we need one
k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
namespace: "{{ kiali_vars.deployment.namespace }}"
name: kiali-signing-key
labels: "{{ kiali_resource_metadata_labels }}"
type: Opaque
data:
key: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters,digits') | b64encode }}"
when:
- kiali_vars.login_token.signing_key == ""
- signing_key_secret_raw is defined
- signing_key_secret_raw.resources is defined
- signing_key_secret_raw.resources | length == 0
# Because we must use a fixed name for the secret, we need to attach a label to indicate this Kiali install will be using it.
# This allows multiple Kiali instances deployed in the same namespace to share the secret. This secret won't be removed
# as long as our label exists on the secret resource.
- name: Add label to kiali-signing-key secret to make it known this Kiali instance will be using it
vars:
the_label: "{{ 'kiali.io/' + ((kiali_vars.deployment.instance_name + '.') if kiali_vars.deployment.instance_name != 'kiali' else '') + 'member-of' }}"
k8s:
state: present
definition: |
apiVersion: v1
kind: Secret
metadata:
namespace: "{{ kiali_vars.deployment.namespace }}"
name: kiali-signing-key
labels:
{{ the_label }}: {{ kiali_vars.deployment.namespace }}
when:
- kiali_vars.login_token.signing_key == ""
- name: Point signing key to the generated secret
set_fact:
kiali_vars: "{{ kiali_vars | combine({'login_token': {'signing_key': 'secret:kiali-signing-key:key'}}, recursive=True) }}"
when:
- kiali_vars.login_token.signing_key == ""
# Some credentials in the config can be overridden by secrets that are to be mounted on the file system.
# Prepare these overrides that need to be defined as volumes in the deployment.
- name: Prepare secret volumes for external services
vars:
kiali_deployment_secret_volumes_yaml: |-
{# Initialize #}
{% set d = {} %}
{# Prepare the secret volume for prometheus password #}
{% if kiali_vars.external_services.prometheus.auth.password | regex_search('secret:.+:.+') %}
{% set d = d | combine({'prometheus-password': {'secret_name': kiali_vars.external_services.prometheus.auth.password | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.prometheus.auth.password | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for prometheus token #}
{% if kiali_vars.external_services.prometheus.auth.token | regex_search('secret:.+:.+') %}
{% set d = d | combine({'prometheus-token': {'secret_name': kiali_vars.external_services.prometheus.auth.token | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.prometheus.auth.token | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for tracing password #}
{% if kiali_vars.external_services.tracing.enabled|bool == True and kiali_vars.external_services.tracing.auth.password | regex_search('secret:.+:.+') %}
{% set d = d | combine({'tracing-password': {'secret_name': kiali_vars.external_services.tracing.auth.password | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.tracing.auth.password | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for tracing token #}
{% if kiali_vars.external_services.tracing.enabled|bool == True and kiali_vars.external_services.tracing.auth.token | regex_search('secret:.+:.+') %}
{% set d = d | combine({'tracing-token': {'secret_name': kiali_vars.external_services.tracing.auth.token | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.tracing.auth.token | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for grafana password #}
{% if kiali_vars.external_services.grafana.enabled|bool == True and kiali_vars.external_services.grafana.auth.password | regex_search('secret:.+:.+') %}
{% set d = d | combine({'grafana-password': {'secret_name': kiali_vars.external_services.grafana.auth.password | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.grafana.auth.password | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for grafana token #}
{% if kiali_vars.external_services.grafana.enabled|bool == True and kiali_vars.external_services.grafana.auth.token | regex_search('secret:.+:.+') %}
{% set d = d | combine({'grafana-token': {'secret_name': kiali_vars.external_services.grafana.auth.token | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.external_services.grafana.auth.token | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Prepare the secret volume for login token signing key #}
{% if kiali_vars.login_token.signing_key | regex_search('secret:.+:.+') %}
{% set d = d | combine({'login-token-signing-key': {'secret_name': kiali_vars.login_token.signing_key | regex_replace('secret:(.+):.+', '\\1'), 'secret_key': kiali_vars.login_token.signing_key | regex_replace('secret:.+:(.+)', '\\1') }}) %}
{% endif %}
{# Set the yaml to the new dict #}
{{ d | to_nice_yaml }}
set_fact:
kiali_deployment_secret_volumes: "{{ kiali_deployment_secret_volumes_yaml | from_yaml }}"
# Prepare to mount remote cluster secrets. These must exist in the Kiali deployment namespace because that is required in order to mount them to the pod.
- set_fact:
kiali_deployment_remote_cluster_secret_volumes: {}
- name: Autodetect remote cluster secrets within the Kiali deployment namespace
vars:
all_remote_cluster_secrets: "{{ query(k8s_plugin, namespace=kiali_vars.deployment.namespace, api_version='v1', kind='Secret', label_selector=kiali_vars.kiali_feature_flags.clustering.autodetect_secrets.label) }}"
loop: "{{ all_remote_cluster_secrets }}"
set_fact:
kiali_deployment_remote_cluster_secret_volumes: "{{ kiali_deployment_remote_cluster_secret_volumes | combine({ item.metadata.annotations['kiali.io/cluster']|default(item.metadata.name): {'secret_name': item.metadata.name }}) }}"
when:
- kiali_vars.kiali_feature_flags.clustering.autodetect_secrets.enabled
- name: Prepare the manually declared remote clusters
loop: "{{ kiali_vars.kiali_feature_flags.clustering.clusters }}"
set_fact:
kiali_deployment_remote_cluster_secret_volumes: "{{ kiali_deployment_remote_cluster_secret_volumes | combine({ item.name: {'secret_name': item.secret_name }}) }}"
when:
- kiali_vars.kiali_feature_flags.clustering.clusters | length > 0
# The following few tasks read the current Kiali configmap (if one exists) in order to figure out what
# namespaces are no longer accessible. Those namespaces will have their Kiali roles removed.
# They will also have the Kiali labels removed.
- name: Find current configmap, if it exists
set_fact:
current_configmap: "{{ lookup(k8s_plugin, resource_name=kiali_vars.deployment.instance_name, namespace=kiali_vars.deployment.namespace, api_version='v1', kind='ConfigMap') }}"
- name: Find some current configuration settings
set_fact:
current_accessible_namespaces: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.accessible_namespaces') }}"
current_label_selector_include: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('api.namespaces.label_selector_include') }}"
current_view_only_mode: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.view_only_mode') }}"
current_image_name: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.image_name') }}"
current_image_version: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.image_version') }}"
current_instance_name: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.instance_name') }}"
current_auth_strategy: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('auth.strategy') }}"
current_cluster_wide_access: "{{ current_configmap.data['config.yaml'] | from_yaml | json_query('deployment.cluster_wide_access') }}"
when:
- current_configmap is defined
- current_configmap.data is defined
- current_configmap.data['config.yaml'] is defined
# Because we need to remove the labels that were created before (this only happens when cluster wide access was not given),
# we must not allow the user to change the label_selector_include. So if cluster wide access is not given but the
# label_selector_include is being changed, we need to abort since we won't know what the old labels were. If
# cluster wide access is currently True then we know we didn't create labels before so we can allow label_selector_include to change.
#
# Now that there is an independent cluster_wide_access setting introduced, we have to remember it did not exist in older Kiali versions.
# If current_cluster_wide_access is defined, that does not mean it was set - in older versions that setting never existed.
# If current_cluster_wide_access == "", that means the value was not set in the ConfigMap - so consider that as "undefined" or "not set".
# Therefore, current_cluster_wide_access|bool != True is only significant if current_cluster_wide_access != "".
# Cluster wide access was given to the current installation if
# (current_cluster_wide_access == "" AND current_accessible_namespaces == '**') [to take into account older versions]
# OR (current_cluster_wide_access != "" AND current_cluster_wide_access|bool == True) [for versions when this new setting was added].
# If current_cluster_wide_access is defined but "", this means it is an old install and we know cluster_wide_access is true only when AN=**.
# This task ensures if current_cluster_wide_access is defined its value is always correctly set to either True or False.
- name: Determine current cluster wide access in backward compatible way
set_fact:
current_cluster_wide_access: "{{ '**' in current_accessible_namespace }}"
when:
- current_accessible_namespace is defined
- current_cluster_wide_access == ""
- name: Do not allow user to change label_selector_include
fail:
msg: "The api.namespaces.label_selector_include cannot be changed to a different value. It was [{{ current_label_selector_include }}] but is now configured to be [{{ kiali_vars.api.namespaces.label_selector_include }}]. In order to install Kiali with a different label selector than what was used before, please uninstall Kiali first."
when:
- current_accessible_namespaces is defined
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == False
- current_label_selector_include is defined
- kiali_vars.api.namespaces.label_selector_include is defined
- current_label_selector_include != kiali_vars.api.namespaces.label_selector_include
- name: Determine if we are moving to cluster-wide-access in which case we need to pretend to make all namespaces inaccessible so the Roles are removed
set_fact:
no_longer_accessible_namespaces: "{{ current_accessible_namespaces }}"
when:
- current_accessible_namespaces is defined
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == False
- kiali_vars.deployment.cluster_wide_access == True
- name: Determine the namespaces that were previously accessible but are now inaccessible
set_fact:
no_longer_accessible_namespaces: "{{ current_accessible_namespaces | difference(kiali_vars.deployment.accessible_namespaces) }}"
when:
- no_longer_accessible_namespaces is not defined
- current_accessible_namespaces is defined
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == False
- kiali_vars.deployment.cluster_wide_access == False
- include_tasks: update-status-progress.yml
vars:
status_progress_message: "Deleting obsolete roles"
- name: Delete all additional Kiali roles from namespaces that Kiali no longer has access to
include_tasks: remove-roles.yml
vars:
role_namespaces: "{{ no_longer_accessible_namespaces }}"
when:
- no_longer_accessible_namespaces is defined
- name: Delete Kiali cluster roles if no longer given special access to all namespaces
include_tasks: remove-clusterroles.yml
when:
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == True
- kiali_vars.deployment.cluster_wide_access == False
# Role Bindings are always "view-only" unless auth.strategy is anonymous and view_only_mode is false.
# If the view_only_mode or auth.strategy changes, we'll delete the roles to make sure we create the correct ones.
# We need to see if the currently installed role binding is view-only - this is used to not break upgrades. See: https://github.com/kiali/kiali/issues/5695
- name: Determine if the currently installed role binding in the deployment namespace is view-only
vars:
current_rolebinding: "{{ query(k8s_plugin, resource_name=kiali_vars.deployment.instance_name, namespace=kiali_vars.deployment.namespace, api_version='rbac.authorization.k8s.io/v1', kind=role_binding_kind, errors='ignore') }}"
set_fact:
current_rolebinding_view_only: "{{ (current_rolebinding | length == 1) and (current_rolebinding[0].roleRef.name is regex('^.*-viewer$')) }}"
- name: Delete all Kiali roles from namespaces if view_only_mode or auth.strategy is changing since role bindings are immutable
include_tasks: remove-roles.yml
vars:
role_namespaces: "{{ kiali_vars.deployment.accessible_namespaces }}"
when:
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == False
- kiali_vars.deployment.cluster_wide_access == False
- current_view_only_mode is defined
- current_auth_strategy is defined
- (current_view_only_mode|bool != kiali_vars.deployment.view_only_mode|bool) or (current_auth_strategy != kiali_vars.auth.strategy) or (current_rolebinding_view_only|bool == False and kiali_vars.auth.strategy != 'anonymous')
- name: Delete Kiali cluster roles if view_only_mode or auth.strategy is changing since cluster role bindings are immutable
include_tasks: remove-clusterroles.yml
when:
- current_cluster_wide_access is defined
- current_cluster_wide_access|bool == True
- kiali_vars.deployment.cluster_wide_access == True
- current_view_only_mode is defined
- current_auth_strategy is defined
- (current_view_only_mode|bool != kiali_vars.deployment.view_only_mode|bool) or (current_auth_strategy != kiali_vars.auth.strategy) or (current_rolebinding_view_only|bool == False and kiali_vars.auth.strategy != 'anonymous')
- include_tasks: update-status-progress.yml
vars:
status_progress_message: "Processing namespace labels"
- name: Remove Kiali label from namespaces that Kiali no longer has access to
vars:
# everything to the left of the = is the name of the label we want to remove
the_namespace_label_name: "{{ current_label_selector_include | regex_replace('^(.*)=.*$', '\\1') }}"
# if a namespace happened to have been deleted, we do not want to (nor can we) resurrect it, hence we use state=patched
k8s:
state: patched
definition: |
{% for namespace in no_longer_accessible_namespaces %}
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ namespace }}"
labels:
{{ the_namespace_label_name }}: null
...
{% endfor %}
when:
- no_longer_accessible_namespaces is defined
- current_label_selector_include is defined
- name: Create additional Kiali label on all accessible namespaces
vars:
namespaces: "{{ kiali_vars.deployment.accessible_namespaces }}"
# everything to the left of the = is the label name; to the right is the label value
the_namespace_label_name: "{{ kiali_vars.api.namespaces.label_selector_include | regex_replace('^(.*)=.*$', '\\1') }}"
the_namespace_label_value: "{{ kiali_vars.api.namespaces.label_selector_include | regex_replace('^.*=(.*)$', '\\1') }}"
k8s:
state: patched
definition: |
{% for namespace in namespaces %}
---
apiVersion: v1
kind: Namespace
metadata:
name: "{{ namespace }}"
labels:
{{ the_namespace_label_name }}: "{{ the_namespace_label_value }}"
...
{% endfor %}
when:
- kiali_vars.deployment.cluster_wide_access == False
- name: Delete Kiali deployment if image is changing - this uninstalled any old version of Kiali that might be running
k8s:
state: absent
api_version: apps/v1
kind: Deployment
namespace: "{{ kiali_vars.deployment.namespace }}"
name: "{{ kiali_vars.deployment.instance_name }}"
when:
- current_image_name is defined and current_image_version is defined
- (current_image_name != kiali_vars.deployment.image_name) or (current_image_version != kiali_vars.deployment.image_version)
# Get the deployment's custom annotation we set that tells us when we last updated the Deployment.
# We need this to ensure the Deployment we update retains this same timestamp unless changes are made
# that requires a pod restart - in which case we update this timestamp.
- name: Find current deployment, if it exists
set_fact:
current_deployment: "{{ lookup(k8s_plugin, resource_name=kiali_vars.deployment.instance_name, namespace=kiali_vars.deployment.namespace, api_version='apps/v1', kind='Deployment') }}"
- name: Get current deployment last-updated annotation timestamp from existing deployment
set_fact:
current_deployment_last_updated: "{{ current_deployment.spec.template.metadata.annotations['operator.kiali.io/last-updated'] if current_deployment.spec.template.metadata.annotations['operator.kiali.io/last-updated'] is defined else lookup('pipe','date') }}"
deployment_is_new: false
when:
- current_deployment is defined
- current_deployment.spec is defined
- current_deployment.spec.template is defined
- current_deployment.spec.template.metadata is defined
- current_deployment.spec.template.metadata.annotations is defined
- name: Set current deployment last-updated annotation timestamp for new deployments
set_fact:
current_deployment_last_updated: "{{ lookup('pipe','date') }}"
deployment_is_new: true
when:
- current_deployment_last_updated is not defined
# Now deploy all resources for the specific cluster environment
- name: Execute for OpenShift environment
include_tasks: openshift/os-main.yml
vars:
deployment_last_updated: "{{ current_deployment_last_updated }}"
when:
- is_openshift == True
- name: Execute for Kubernetes environment
include_tasks: kubernetes/k8s-main.yml
vars:
deployment_last_updated: "{{ current_deployment_last_updated }}"
when:
- is_k8s == True
# If something changed that can only be picked up when the Kiali pod starts up, then restart the Kiali pod using a rolling restart
# We do this by checking the processed_resources_dict created by process-resources.yml task. If there is a map key
# with the kind (ConfigMap) with the name of our config map appended to it ("-" + the kiali instanance name) see if that config map changed.
# If it did, we need to restart the kiali pod so it can re-read the new config.
- name: Force the Kiali pod to restart if necessary
vars:
keyname: "{{ 'ConfigMap-' + kiali_vars.deployment.instance_name }}"
updated_deployment: "{{ lookup(k8s_plugin, resource_name=kiali_vars.deployment.instance_name, namespace=kiali_vars.deployment.namespace, api_version='apps/v1', kind='Deployment') | combine({'spec': {'template': {'metadata': {'annotations': {'operator.kiali.io/last-updated': lookup('pipe','date') }}}}}, recursive=True) }}"
k8s:
state: "present"
definition: "{{ updated_deployment }}"
when:
- deployment_is_new == False
- processed_resources_dict is defined
- processed_resources_dict[keyname] is defined
- processed_resources_dict[keyname].changed == True
- processed_resources_dict[keyname].method == "patch"
# Can't just populate with the list of namespaces - see https://github.com/operator-framework/operator-sdk-ansible-util/issues/12
# So instead - if the list of namespaces is manageable, store them in a comma-separate list.
# Otherwise, we'll just log the count. The purpose of this accessibleNamespaces status field is
# just to inform the user how many namespaces the operator processed.
- include_tasks: update-status-progress.yml
vars:
status_progress_message: "Finished all resource creation"
status_vars:
deployment:
accessibleNamespaces: "{{ ('Number of accessible namespaces (including control plane namespace): ' + (kiali_vars.deployment.accessible_namespaces | length | string)) if (kiali_vars.deployment.accessible_namespaces | length > 20) else (kiali_vars.deployment.accessible_namespaces | join(',')) }}"