11package io .javaoperatorsdk .operator ;
22
3+ import java .util .Arrays ;
34import java .util .UUID ;
45import java .util .concurrent .CompletableFuture ;
56
67import org .slf4j .Logger ;
78import org .slf4j .LoggerFactory ;
89
10+ import io .fabric8 .kubernetes .api .model .authorization .v1 .*;
911import io .fabric8 .kubernetes .client .KubernetesClient ;
1012import io .fabric8 .kubernetes .client .extended .leaderelection .LeaderCallbacks ;
1113import io .fabric8 .kubernetes .client .extended .leaderelection .LeaderElectionConfig ;
@@ -20,18 +22,26 @@ public class LeaderElectionManager {
2022
2123 private static final Logger log = LoggerFactory .getLogger (LeaderElectionManager .class );
2224
25+ public static final String NO_PERMISSION_TO_LEASE_RESOURCE_MESSAGE =
26+ "No permission to lease resource." ;
27+
2328 private LeaderElector leaderElector = null ;
2429 private final ControllerManager controllerManager ;
2530 private String identity ;
2631 private CompletableFuture <?> leaderElectionFuture ;
32+ private KubernetesClient client ;
33+ private String leaseName ;
34+ private String leaseNamespace ;
2735
2836 public LeaderElectionManager (ControllerManager controllerManager ) {
2937 this .controllerManager = controllerManager ;
3038 }
3139
3240 public void init (LeaderElectionConfiguration config , KubernetesClient client ) {
41+ this .client = client ;
3342 this .identity = identity (config );
34- final var leaseNamespace =
43+ this .leaseName = config .getLeaseName ();
44+ leaseNamespace =
3545 config .getLeaseNamespace ().orElseGet (
3646 () -> ConfigurationServiceProvider .instance ().getClientConfiguration ().getNamespace ());
3747 if (leaseNamespace == null ) {
@@ -40,20 +50,19 @@ public void init(LeaderElectionConfiguration config, KubernetesClient client) {
4050 log .error (message );
4151 throw new IllegalArgumentException (message );
4252 }
43- final var lock = new LeaseLock (leaseNamespace , config . getLeaseName () , identity );
53+ final var lock = new LeaseLock (leaseNamespace , leaseName , identity );
4454 // releaseOnCancel is not used in the underlying implementation
4555 leaderElector =
4656 new LeaderElectorBuilder (
4757 client , ExecutorServiceManager .instance ().executorService ())
48- .withConfig (
49- new LeaderElectionConfig (
50- lock ,
51- config .getLeaseDuration (),
52- config .getRenewDeadline (),
53- config .getRetryPeriod (),
54- leaderCallbacks (),
55- true ,
56- config .getLeaseName ()))
58+ .withConfig (new LeaderElectionConfig (
59+ lock ,
60+ config .getLeaseDuration (),
61+ config .getRenewDeadline (),
62+ config .getRetryPeriod (),
63+ leaderCallbacks (),
64+ true ,
65+ config .getLeaseName ()))
5766 .build ();
5867 }
5968
@@ -90,6 +99,7 @@ private String identity(LeaderElectionConfiguration config) {
9099
91100 public void start () {
92101 if (isLeaderElectionEnabled ()) {
102+ checkLeaseAccess ();
93103 leaderElectionFuture = leaderElector .start ();
94104 }
95105 }
@@ -99,4 +109,21 @@ public void stop() {
99109 leaderElectionFuture .cancel (false );
100110 }
101111 }
112+
113+ private void checkLeaseAccess () {
114+ var verbs = Arrays .asList ("create" , "update" , "get" );
115+ SelfSubjectRulesReview review = new SelfSubjectRulesReview ();
116+ review .setSpec (new SelfSubjectRulesReviewSpecBuilder ().withNamespace (leaseNamespace ).build ());
117+ var reviewResult = client .resource (review ).create ();
118+ log .debug ("SelfSubjectRulesReview result: {}" , reviewResult );
119+ var foundRule = reviewResult .getStatus ().getResourceRules ().stream ()
120+ .filter (rule -> rule .getApiGroups ().contains ("coordination.k8s.io" )
121+ && rule .getResources ().contains ("leases" )
122+ && (rule .getVerbs ().containsAll (verbs )) || rule .getVerbs ().contains ("*" ))
123+ .findAny ();
124+ if (foundRule .isEmpty ()) {
125+ throw new OperatorException (NO_PERMISSION_TO_LEASE_RESOURCE_MESSAGE +
126+ " in namespace: " + leaseNamespace );
127+ }
128+ }
102129}
0 commit comments