blob: c238293b1eac70b45c42afc0eaa5856fb09a24b7 [file] [log] [blame]
Scott Baker3fd18e52018-04-17 09:18:21 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""
17 sync_principal.py
18
19 Synchronize Principals. Principals correspond roughly to Kubernetes ServiceAccounts.
20"""
21
Scott Bakera30fae72019-02-01 16:14:43 -080022from xossynchronizer.steps.syncstep import SyncStep
23from xossynchronizer.modelaccessor import Principal
Scott Baker3fd18e52018-04-17 09:18:21 -070024
25from xosconfig import Config
26from multistructlog import create_logger
27
Scott Baker3fd18e52018-04-17 09:18:21 -070028log = create_logger(Config().get('logging'))
29
30class SyncPrincipal(SyncStep):
31
32 """
33 SyncPrincipal
34
35 Implements sync step for syncing Principals.
36 """
37
38 provides = [Principal]
39 observes = Principal
40 requested_interval = 0
41
42 def __init__(self, *args, **kwargs):
43 super(SyncPrincipal, self).__init__(*args, **kwargs)
Scott Baker13e953c2018-05-17 09:19:15 -070044 self.init_kubernetes_client()
45
46 def init_kubernetes_client(self):
47 from kubernetes.client.rest import ApiException
48 from kubernetes import client as kubernetes_client, config as kubernetes_config
Scott Baker3fd18e52018-04-17 09:18:21 -070049 kubernetes_config.load_incluster_config()
Scott Baker13e953c2018-05-17 09:19:15 -070050 self.kubernetes_client = kubernetes_client
51 self.v1core = kubernetes_client.CoreV1Api()
52 self.ApiException = ApiException
Scott Baker3fd18e52018-04-17 09:18:21 -070053
54 def get_service_account(self, o):
55 """ Given an XOS Principal object, read the corresponding ServiceAccount from Kubernetes.
56 return None if no ServiceAccount exists.
57 """
58 try:
Scott Baker13e953c2018-05-17 09:19:15 -070059 service_account = self.v1core.read_namespaced_service_account(o.name, o.trust_domain.name)
60 except self.ApiException, e:
Scott Baker3fd18e52018-04-17 09:18:21 -070061 if e.status == 404:
62 return None
63 raise
64 return service_account
65
66 def fetch_pending(self, deleted):
67 """ Figure out which Principals are interesting to the K8s synchronizer.
68 As each Principal exists within a Trust Domain, this reduces to figuring out which Trust Domains are
69 interesting.
70 """
71 objs = super(SyncPrincipal, self).fetch_pending(deleted)
72 for obj in objs[:]:
73 # If the Principal isn't in a TrustDomain, then the K8s synchronizer can't do anything with it
74 if not obj.trust_domain:
75 objs.remove(obj)
76 continue
77
78 # If the Principal's TrustDomain isn't part of the K8s service, then it's someone else's principal
79 if "KubernetesService" not in obj.trust_domain.owner.leaf_model.class_names:
80 objs.remove(obj)
81 return objs
82
83 def sync_record(self, o):
84 service_account = self.get_service_account(o)
85 if not service_account:
Scott Baker13e953c2018-05-17 09:19:15 -070086 service_account = self.kubernetes_client.V1ServiceAccount()
87 service_account.metadata = self.kubernetes_client.V1ObjectMeta(name=o.name)
Scott Baker3fd18e52018-04-17 09:18:21 -070088
Scott Baker13e953c2018-05-17 09:19:15 -070089 service_account = self.v1core.create_namespaced_service_account(o.trust_domain.name, service_account)
Scott Baker3fd18e52018-04-17 09:18:21 -070090
91 if (not o.backend_handle):
92 o.backend_handle = service_account.metadata.self_link
93 o.save(update_fields=["backend_handle"])
94
Scott Baker393d0152018-05-21 09:17:49 -070095 def delete_record(self, o):
96 principal = self.get_service_account(o)
97 if not principal:
98 log.info("Kubernetes service account does not exist; Nothing to delete.", o=o)
99 return
100 delete_options = self.kubernetes_client.V1DeleteOptions()
101 self.v1core.delete_namespaced_service_account(o.name, o.trust_domain.name, delete_options)
102 log.info("Deleted Principal from kubernetes", handle=o.backend_handle)