2018-08-09 02:38:05 -04:00
|
|
|
# Copyright (c) 2018 Samsung Electronics Co.,Ltd
|
|
|
|
# All Rights Reserved.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
# not use this file except in compliance with the License. You may obtain
|
|
|
|
# a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
# License for the specific language governing permissions and limitations
|
|
|
|
# under the License.
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
import urllib
|
|
|
|
|
2020-02-28 08:29:08 +01:00
|
|
|
import netaddr
|
2019-11-29 08:38:32 +01:00
|
|
|
from openstack import exceptions as os_exc
|
2018-12-17 12:53:51 +00:00
|
|
|
from oslo_config import cfg
|
|
|
|
from oslo_log import log
|
2018-11-07 18:46:07 +01:00
|
|
|
from oslo_serialization import jsonutils
|
|
|
|
|
2018-12-08 16:35:35 +00:00
|
|
|
from kuryr_kubernetes import clients
|
2018-11-07 18:46:07 +01:00
|
|
|
from kuryr_kubernetes import constants
|
2018-08-09 02:38:05 -04:00
|
|
|
from kuryr_kubernetes import exceptions as k_exc
|
2018-11-07 18:46:07 +01:00
|
|
|
from kuryr_kubernetes import utils
|
2018-08-09 02:38:05 -04:00
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
|
2018-12-08 16:35:35 +00:00
|
|
|
OPERATORS_WITH_VALUES = [constants.K8S_OPERATOR_IN,
|
|
|
|
constants.K8S_OPERATOR_NOT_IN]
|
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
2018-08-09 02:38:05 -04:00
|
|
|
|
|
|
|
def get_network_id(subnets):
|
2019-12-09 15:22:19 +01:00
|
|
|
ids = list(set(net.id for net in subnets.values()))
|
2018-08-09 02:38:05 -04:00
|
|
|
|
|
|
|
if len(ids) != 1:
|
|
|
|
raise k_exc.IntegrityError(
|
|
|
|
"Subnet mapping %(subnets)s is not valid: "
|
|
|
|
"%(num_networks)s unique networks found" %
|
|
|
|
{'subnets': subnets, 'num_networks': len(ids)})
|
|
|
|
|
|
|
|
return ids[0]
|
|
|
|
|
|
|
|
|
|
|
|
def get_port_name(pod):
|
|
|
|
return "%(namespace)s/%(name)s" % pod['metadata']
|
|
|
|
|
|
|
|
|
|
|
|
def get_device_id(pod):
|
|
|
|
return pod['metadata']['uid']
|
|
|
|
|
|
|
|
|
|
|
|
def get_host_id(pod):
|
|
|
|
return pod['spec']['nodeName']
|
2018-11-07 18:46:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
def get_pod_state(pod):
|
|
|
|
try:
|
|
|
|
annotations = pod['metadata']['annotations']
|
|
|
|
state_annotation = annotations[constants.K8S_ANNOTATION_VIF]
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
state_annotation = jsonutils.loads(state_annotation)
|
|
|
|
state = utils.extract_pod_annotation(state_annotation)
|
|
|
|
return state
|
2018-12-10 13:06:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
def is_host_network(pod):
|
|
|
|
return pod['spec'].get('hostNetwork', False)
|
2018-12-08 16:35:35 +00:00
|
|
|
|
|
|
|
|
2018-12-16 11:51:29 +02:00
|
|
|
def get_pods(selector, namespace=None):
|
2018-12-07 18:31:50 +01:00
|
|
|
"""Return a k8s object list with the pods matching the selector.
|
|
|
|
|
|
|
|
It accepts an optional parameter to state the namespace where the pod
|
|
|
|
selector will be apply. If empty namespace is passed, then the pod
|
|
|
|
selector is applied in all namespaces.
|
|
|
|
|
|
|
|
param selector: k8s selector of types matchLabels or matchExpressions
|
|
|
|
param namespace: namespace name where the selector will be applied. If
|
|
|
|
None, the pod selector is applied in all namespaces
|
2018-12-16 11:51:29 +02:00
|
|
|
return: k8s list object containing all matching pods
|
2018-12-07 18:31:50 +01:00
|
|
|
|
|
|
|
"""
|
2018-12-08 16:35:35 +00:00
|
|
|
kubernetes = clients.get_kubernetes_client()
|
2018-12-24 13:01:12 +01:00
|
|
|
|
|
|
|
svc_selector = selector.get('selector')
|
|
|
|
if svc_selector:
|
|
|
|
labels = replace_encoded_characters(svc_selector)
|
|
|
|
else:
|
|
|
|
labels = selector.get('matchLabels', None)
|
2018-12-08 16:35:35 +00:00
|
|
|
if labels:
|
2018-12-24 13:01:12 +01:00
|
|
|
# Removing pod-template-hash as pods will not have it and
|
|
|
|
# otherwise there will be no match
|
|
|
|
labels.pop('pod-template-hash', None)
|
|
|
|
labels = replace_encoded_characters(labels)
|
|
|
|
|
|
|
|
exps = selector.get('matchExpressions', None)
|
|
|
|
if exps:
|
|
|
|
exps = ', '.join(format_expression(exp) for exp in exps)
|
|
|
|
if labels:
|
2020-02-28 12:00:19 +01:00
|
|
|
expressions = urllib.parse.quote("," + exps)
|
2018-12-24 13:01:12 +01:00
|
|
|
labels += expressions
|
|
|
|
else:
|
2020-02-28 12:00:19 +01:00
|
|
|
labels = urllib.parse.quote(exps)
|
2018-12-08 16:35:35 +00:00
|
|
|
|
2018-12-07 18:31:50 +01:00
|
|
|
if namespace:
|
|
|
|
pods = kubernetes.get(
|
|
|
|
'{}/namespaces/{}/pods?labelSelector={}'.format(
|
|
|
|
constants.K8S_API_BASE, namespace, labels))
|
|
|
|
else:
|
|
|
|
pods = kubernetes.get(
|
|
|
|
'{}/pods?labelSelector={}'.format(constants.K8S_API_BASE, labels))
|
2018-12-08 16:35:35 +00:00
|
|
|
|
|
|
|
return pods
|
|
|
|
|
|
|
|
|
2018-12-07 18:31:50 +01:00
|
|
|
def get_namespaces(selector):
|
|
|
|
"""Return a k8s object list with the namespaces matching the selector.
|
|
|
|
|
|
|
|
param selector: k8s selector of types matchLabels or matchExpressions
|
2018-12-16 11:51:29 +02:00
|
|
|
return: k8s list object containing all matching namespaces
|
2018-12-07 18:31:50 +01:00
|
|
|
|
|
|
|
"""
|
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
labels = selector.get('matchLabels', None)
|
|
|
|
if labels:
|
|
|
|
labels = replace_encoded_characters(labels)
|
|
|
|
|
|
|
|
exps = selector.get('matchExpressions', None)
|
|
|
|
if exps:
|
|
|
|
exps = ', '.join(format_expression(exp) for exp in exps)
|
|
|
|
if labels:
|
2020-02-28 12:00:19 +01:00
|
|
|
expressions = urllib.parse.quote("," + exps)
|
2018-12-07 18:31:50 +01:00
|
|
|
labels += expressions
|
|
|
|
else:
|
2020-02-28 12:00:19 +01:00
|
|
|
labels = urllib.parse.quote(exps)
|
2018-12-07 18:31:50 +01:00
|
|
|
|
|
|
|
namespaces = kubernetes.get(
|
|
|
|
'{}/namespaces?labelSelector={}'.format(
|
|
|
|
constants.K8S_API_BASE, labels))
|
|
|
|
|
|
|
|
return namespaces
|
|
|
|
|
|
|
|
|
2018-12-08 16:35:35 +00:00
|
|
|
def format_expression(expression):
|
|
|
|
key = expression['key']
|
|
|
|
operator = expression['operator'].lower()
|
|
|
|
if operator in OPERATORS_WITH_VALUES:
|
|
|
|
values = expression['values']
|
|
|
|
values = str(', '.join(values))
|
|
|
|
values = "(%s)" % values
|
|
|
|
return "%s %s %s" % (key, operator, values)
|
|
|
|
else:
|
|
|
|
if operator == constants.K8S_OPERATOR_DOES_NOT_EXIST:
|
|
|
|
return "!%s" % key
|
|
|
|
else:
|
|
|
|
return key
|
|
|
|
|
|
|
|
|
|
|
|
def replace_encoded_characters(labels):
|
2020-02-28 12:00:19 +01:00
|
|
|
labels = urllib.parse.urlencode(labels)
|
2018-12-08 16:35:35 +00:00
|
|
|
# NOTE(ltomasbo): K8s API does not accept &, so we need to AND
|
|
|
|
# the matchLabels with ',' or '%2C' instead
|
|
|
|
labels = labels.replace('&', ',')
|
|
|
|
return labels
|
2018-12-17 12:53:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def create_security_group_rule(body):
|
2019-11-29 08:38:32 +01:00
|
|
|
os_net = clients.get_network_client()
|
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
sgr = ''
|
2019-11-29 08:38:32 +01:00
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
try:
|
2019-11-29 08:38:32 +01:00
|
|
|
params = dict(body['security_group_rule'])
|
|
|
|
if 'ethertype' in params:
|
|
|
|
# NOTE(gryf): in openstacksdk, there is ether_type attribute in
|
|
|
|
# the security_group_rule object, in CRD we have 'ethertype'
|
|
|
|
# instead, just like it was returned by the neutron client.
|
|
|
|
params['ether_type'] = params['ethertype']
|
|
|
|
del params['ethertype']
|
|
|
|
sgr = os_net.create_security_group_rule(**params)
|
|
|
|
return sgr.id
|
|
|
|
except os_exc.ConflictException as ex:
|
2020-04-30 09:04:53 +02:00
|
|
|
if 'quota' in ex.details.lower():
|
|
|
|
LOG.error("Failed to create security group rule %s: %s", body,
|
|
|
|
ex.details)
|
|
|
|
raise
|
|
|
|
else:
|
|
|
|
LOG.debug("Failed to create already existing security group "
|
|
|
|
"rule %s", body)
|
|
|
|
# Get existent sg rule id from exception message
|
|
|
|
return str(ex).split()[-1][:-1]
|
2019-11-29 08:38:32 +01:00
|
|
|
except os_exc.SDKException:
|
2018-12-17 12:53:51 +00:00
|
|
|
LOG.debug("Error creating security group rule")
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
def delete_security_group_rule(security_group_rule_id):
|
2019-11-29 08:38:32 +01:00
|
|
|
os_net = clients.get_network_client()
|
2018-12-17 12:53:51 +00:00
|
|
|
try:
|
|
|
|
LOG.debug("Deleting sg rule with ID: %s", security_group_rule_id)
|
2019-11-29 08:38:32 +01:00
|
|
|
os_net.delete_security_group_rule(security_group_rule_id)
|
|
|
|
except os_exc.SDKException:
|
2018-12-17 12:53:51 +00:00
|
|
|
LOG.debug("Error deleting security group rule: %s",
|
|
|
|
security_group_rule_id)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2019-06-14 14:07:26 +02:00
|
|
|
def patch_kuryrnetworkpolicy_crd(crd, i_rules, e_rules, pod_selector,
|
|
|
|
np_spec=None):
|
2018-12-17 12:53:51 +00:00
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
crd_name = crd['metadata']['name']
|
|
|
|
if not np_spec:
|
|
|
|
np_spec = crd['spec']['networkpolicy_spec']
|
|
|
|
LOG.debug('Patching KuryrNetPolicy CRD %s' % crd_name)
|
|
|
|
try:
|
2019-02-13 10:45:37 +00:00
|
|
|
kubernetes.patch_crd('spec', crd['metadata']['selfLink'],
|
|
|
|
{'ingressSgRules': i_rules,
|
|
|
|
'egressSgRules': e_rules,
|
|
|
|
'podSelector': pod_selector,
|
|
|
|
'networkpolicy_spec': np_spec})
|
2019-10-21 15:54:57 +00:00
|
|
|
except k_exc.K8sResourceNotFound:
|
|
|
|
LOG.debug('KuryrNetPolicy CRD not found %s', crd_name)
|
2018-12-17 12:53:51 +00:00
|
|
|
except k_exc.K8sClientException:
|
|
|
|
LOG.exception('Error updating kuryrnetpolicy CRD %s', crd_name)
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
def create_security_group_rule_body(
|
2019-04-11 16:46:16 +02:00
|
|
|
security_group_id, direction, port_range_min=None,
|
2020-02-28 08:29:08 +01:00
|
|
|
port_range_max=None, protocol=None, ethertype=None, cidr=None,
|
2019-03-13 15:42:25 +00:00
|
|
|
description="Kuryr-Kubernetes NetPolicy SG rule", namespace=None,
|
|
|
|
pods=None):
|
2018-12-17 12:53:51 +00:00
|
|
|
if not port_range_min:
|
|
|
|
port_range_min = 1
|
|
|
|
port_range_max = 65535
|
|
|
|
elif not port_range_max:
|
|
|
|
port_range_max = port_range_min
|
|
|
|
if not protocol:
|
|
|
|
protocol = 'TCP'
|
2020-02-28 08:29:08 +01:00
|
|
|
|
|
|
|
if not ethertype:
|
|
|
|
ethertype = 'IPv4'
|
|
|
|
if cidr and netaddr.IPNetwork(cidr).version == 6:
|
|
|
|
ethertype = 'IPv6'
|
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
security_group_rule_body = {
|
2019-11-13 11:49:49 +01:00
|
|
|
'security_group_rule': {
|
|
|
|
'ethertype': ethertype,
|
|
|
|
'security_group_id': security_group_id,
|
|
|
|
'description': description,
|
|
|
|
'direction': direction,
|
|
|
|
'protocol': protocol.lower(),
|
|
|
|
'port_range_min': port_range_min,
|
|
|
|
'port_range_max': port_range_max,
|
2018-12-17 12:53:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if cidr:
|
2019-11-13 11:49:49 +01:00
|
|
|
security_group_rule_body['security_group_rule'][
|
|
|
|
'remote_ip_prefix'] = cidr
|
2018-12-30 22:10:51 +00:00
|
|
|
if namespace:
|
|
|
|
security_group_rule_body['namespace'] = namespace
|
2019-03-13 15:42:25 +00:00
|
|
|
if pods:
|
|
|
|
security_group_rule_body['remote_ip_prefixes'] = pods
|
2018-12-17 12:53:51 +00:00
|
|
|
LOG.debug("Creating sg rule body %s", security_group_rule_body)
|
|
|
|
return security_group_rule_body
|
|
|
|
|
|
|
|
|
|
|
|
def get_pod_ip(pod):
|
2019-08-28 13:12:08 +02:00
|
|
|
try:
|
2019-09-26 15:16:09 +00:00
|
|
|
pod_metadata = pod['metadata']['annotations']
|
|
|
|
vif = pod_metadata[constants.K8S_ANNOTATION_VIF]
|
2019-08-28 13:12:08 +02:00
|
|
|
except KeyError:
|
2019-09-26 15:16:09 +00:00
|
|
|
return None
|
2018-12-17 12:53:51 +00:00
|
|
|
vif = jsonutils.loads(vif)
|
|
|
|
vif = vif['versioned_object.data']['default_vif']
|
|
|
|
network = (vif['versioned_object.data']['network']
|
|
|
|
['versioned_object.data'])
|
|
|
|
first_subnet = (network['subnets']['versioned_object.data']
|
|
|
|
['objects'][0]['versioned_object.data'])
|
|
|
|
first_subnet_ip = (first_subnet['ips']['versioned_object.data']
|
|
|
|
['objects'][0]['versioned_object.data']['address'])
|
|
|
|
return first_subnet_ip
|
|
|
|
|
|
|
|
|
2019-08-29 18:31:12 +02:00
|
|
|
def get_annotations(resource, annotation):
|
2018-12-17 12:53:51 +00:00
|
|
|
try:
|
2018-12-30 22:10:51 +00:00
|
|
|
annotations = resource['metadata']['annotations']
|
2019-08-29 18:31:12 +02:00
|
|
|
return annotations[annotation]
|
2018-12-17 12:53:51 +00:00
|
|
|
except KeyError:
|
|
|
|
return None
|
2019-08-29 18:31:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_annotated_labels(resource, annotation_labels):
|
|
|
|
labels_annotation = get_annotations(resource, annotation_labels)
|
|
|
|
if labels_annotation:
|
|
|
|
return jsonutils.loads(labels_annotation)
|
|
|
|
return None
|
2018-12-30 22:10:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_kuryrnetpolicy_crds(namespace=None):
|
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
|
|
|
|
try:
|
|
|
|
if namespace:
|
|
|
|
knp_path = '{}/{}/kuryrnetpolicies'.format(
|
|
|
|
constants.K8S_API_CRD_NAMESPACES, namespace)
|
|
|
|
else:
|
|
|
|
knp_path = constants.K8S_API_CRD_KURYRNETPOLICIES
|
|
|
|
LOG.debug("K8s API Query %s", knp_path)
|
|
|
|
knps = kubernetes.get(knp_path)
|
|
|
|
LOG.debug("Return Kuryr Network Policies with label %s", knps)
|
|
|
|
except k_exc.K8sResourceNotFound:
|
|
|
|
LOG.exception("KuryrNetPolicy CRD not found")
|
|
|
|
raise
|
|
|
|
except k_exc.K8sClientException:
|
|
|
|
LOG.exception("Kubernetes Client Exception")
|
|
|
|
raise
|
|
|
|
return knps
|
|
|
|
|
|
|
|
|
|
|
|
def match_expressions(expressions, labels):
|
|
|
|
for exp in expressions:
|
|
|
|
exp_op = exp['operator'].lower()
|
|
|
|
if labels:
|
|
|
|
if exp_op in OPERATORS_WITH_VALUES:
|
|
|
|
exp_values = exp['values']
|
|
|
|
label_value = labels.get(str(exp['key']), None)
|
|
|
|
if exp_op == constants.K8S_OPERATOR_IN:
|
|
|
|
if label_value is None or label_value not in exp_values:
|
2020-02-21 12:00:03 +01:00
|
|
|
return False
|
2018-12-30 22:10:51 +00:00
|
|
|
elif exp_op == constants.K8S_OPERATOR_NOT_IN:
|
|
|
|
if label_value in exp_values:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
if exp_op == constants.K8S_OPERATOR_EXISTS:
|
|
|
|
exists = labels.get(str(exp['key']), None)
|
|
|
|
if exists is None:
|
|
|
|
return False
|
|
|
|
elif exp_op == constants.K8S_OPERATOR_DOES_NOT_EXIST:
|
|
|
|
exists = labels.get(str(exp['key']), None)
|
|
|
|
if exists is not None:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
if exp_op in (constants.K8S_OPERATOR_IN,
|
|
|
|
constants.K8S_OPERATOR_EXISTS):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def match_labels(crd_labels, labels):
|
|
|
|
for crd_key, crd_value in crd_labels.items():
|
|
|
|
label_value = labels.get(crd_key, None)
|
|
|
|
if not label_value or crd_value != label_value:
|
2020-02-21 12:00:03 +01:00
|
|
|
return False
|
2018-12-30 22:10:51 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def match_selector(selector, labels):
|
|
|
|
crd_labels = selector.get('matchLabels', None)
|
|
|
|
crd_expressions = selector.get('matchExpressions', None)
|
|
|
|
|
|
|
|
match_exp = match_lb = True
|
|
|
|
if crd_expressions:
|
|
|
|
match_exp = match_expressions(crd_expressions,
|
|
|
|
labels)
|
|
|
|
if crd_labels and labels:
|
|
|
|
match_lb = match_labels(crd_labels, labels)
|
|
|
|
return match_exp and match_lb
|
|
|
|
|
|
|
|
|
|
|
|
def get_namespace_subnet_cidr(namespace):
|
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
try:
|
2020-02-10 08:46:03 +01:00
|
|
|
net_crd_path = (f"{constants.K8S_API_CRD_NAMESPACES}/"
|
|
|
|
f"{namespace['metadata']['name']}/kuryrnetworks/"
|
|
|
|
f"{namespace['metadata']['name']}")
|
|
|
|
net_crd = kubernetes.get(net_crd_path)
|
|
|
|
except k_exc.K8sResourceNotFound:
|
|
|
|
LOG.exception('Namespace not yet ready')
|
2018-12-30 22:10:51 +00:00
|
|
|
raise k_exc.ResourceNotReady(namespace)
|
|
|
|
except k_exc.K8sClientException:
|
|
|
|
LOG.exception("Kubernetes Client Exception.")
|
|
|
|
raise
|
2020-02-10 08:46:03 +01:00
|
|
|
try:
|
|
|
|
subnet_cidr = net_crd['status']['subnetCIDR']
|
|
|
|
except KeyError:
|
|
|
|
LOG.exception('Namespace not yet ready')
|
|
|
|
raise k_exc.ResourceNotReady(namespace)
|
|
|
|
return subnet_cidr
|
2019-02-13 10:04:08 +01:00
|
|
|
|
|
|
|
|
2020-01-27 14:19:41 +01:00
|
|
|
def tag_neutron_resources(resources):
|
|
|
|
"""Set tags to the provided resources.
|
|
|
|
|
|
|
|
param resources: list of openstacksdk objects to tag.
|
|
|
|
"""
|
2019-02-13 10:04:08 +01:00
|
|
|
tags = CONF.neutron_defaults.resource_tags
|
2020-01-27 14:19:41 +01:00
|
|
|
if not tags:
|
|
|
|
return
|
|
|
|
|
|
|
|
os_net = clients.get_network_client()
|
|
|
|
for res in resources:
|
|
|
|
try:
|
|
|
|
os_net.set_tags(res, tags=tags)
|
2020-01-29 09:07:21 +01:00
|
|
|
except os_exc.SDKException:
|
2020-01-27 14:19:41 +01:00
|
|
|
LOG.warning("Failed to tag %s with %s. Ignoring, but this is "
|
|
|
|
"still unexpected.", res, tags, exc_info=True)
|
2019-02-15 13:41:33 +00:00
|
|
|
|
|
|
|
|
2019-05-27 04:56:32 -04:00
|
|
|
def get_services(namespace=None):
|
2019-02-15 13:41:33 +00:00
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
try:
|
2019-05-27 04:56:32 -04:00
|
|
|
if namespace:
|
|
|
|
services = kubernetes.get(
|
|
|
|
'{}/namespaces/{}/services'.format(constants.K8S_API_BASE,
|
|
|
|
namespace))
|
|
|
|
else:
|
|
|
|
services = kubernetes.get(
|
|
|
|
'{}/services'.format(constants.K8S_API_BASE))
|
2019-02-15 13:41:33 +00:00
|
|
|
except k_exc.K8sClientException:
|
2019-05-27 04:56:32 -04:00
|
|
|
LOG.exception('Exception when getting K8s services.')
|
2019-02-15 13:41:33 +00:00
|
|
|
raise
|
|
|
|
return services
|
2019-02-28 22:46:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
def service_matches_affected_pods(service, pod_selectors):
|
|
|
|
"""Returns if the service is affected by the pod selectors
|
|
|
|
|
|
|
|
Checks if the service selector matches the labelSelectors of
|
|
|
|
NetworkPolicies.
|
|
|
|
|
|
|
|
param service: k8s service
|
|
|
|
param pod_selectors: a list of kubernetes labelSelectors
|
|
|
|
return: True if the service is selected by any of the labelSelectors
|
|
|
|
and False otherwise.
|
|
|
|
"""
|
|
|
|
svc_selector = service['spec'].get('selector')
|
2019-09-29 21:58:40 +00:00
|
|
|
if not svc_selector:
|
|
|
|
return False
|
2019-02-28 22:46:22 +00:00
|
|
|
for selector in pod_selectors:
|
|
|
|
if match_selector(selector, svc_selector):
|
|
|
|
return True
|
|
|
|
return False
|
2019-03-13 15:42:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_namespaced_pods(namespace=None):
|
|
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
if namespace:
|
|
|
|
namespace = namespace['metadata']['name']
|
|
|
|
pods = kubernetes.get(
|
|
|
|
'{}/namespaces/{}/pods'.format(
|
|
|
|
constants.K8S_API_BASE, namespace))
|
|
|
|
else:
|
|
|
|
pods = kubernetes.get(
|
|
|
|
'{}/pods'.format(
|
|
|
|
constants.K8S_API_BASE))
|
|
|
|
return pods
|
|
|
|
|
|
|
|
|
|
|
|
def get_container_ports(containers, np_port_name, pod):
|
|
|
|
matched_ports = []
|
|
|
|
if is_host_network(pod):
|
|
|
|
return matched_ports
|
|
|
|
for container in containers:
|
|
|
|
for container_port in container.get('ports', []):
|
|
|
|
if container_port.get('name') == np_port_name:
|
|
|
|
container_port = container_port.get('containerPort')
|
|
|
|
if container_port not in matched_ports:
|
|
|
|
matched_ports.append((pod, container_port))
|
|
|
|
return matched_ports
|
|
|
|
|
|
|
|
|
|
|
|
def get_ports(resource, port):
|
|
|
|
"""Returns values of ports that have a given port name
|
|
|
|
|
|
|
|
Retrieves the values of ports, defined in the containers
|
|
|
|
associated to the resource, that has its name matching a
|
|
|
|
given port.
|
|
|
|
|
|
|
|
param resource: k8s Pod or Namespace
|
|
|
|
param port: a dict containing a port and protocol
|
|
|
|
return: A list of tuples of port values and associated pods
|
|
|
|
"""
|
|
|
|
containers = resource['spec'].get('containers')
|
|
|
|
ports = []
|
|
|
|
np_port = port.get('port')
|
|
|
|
if containers:
|
|
|
|
ports.extend(get_container_ports(containers, np_port, resource))
|
|
|
|
else:
|
|
|
|
pods = get_namespaced_pods(resource).get('items')
|
|
|
|
for pod in pods:
|
|
|
|
containers = pod['spec']['containers']
|
|
|
|
ports.extend(get_container_ports(
|
|
|
|
containers, np_port, pod))
|
|
|
|
return ports
|
|
|
|
|
|
|
|
|
|
|
|
def get_namespace(namespace_name):
|
|
|
|
kubernetes = clients.get_kubernetes_client()
|
2019-10-03 16:18:33 +00:00
|
|
|
try:
|
|
|
|
return kubernetes.get(
|
|
|
|
'{}/namespaces/{}'.format(
|
|
|
|
constants.K8S_API_BASE, namespace_name))
|
|
|
|
except k_exc.K8sResourceNotFound:
|
|
|
|
LOG.debug("Namespace not found: %s",
|
|
|
|
namespace_name)
|
|
|
|
return None
|
2019-03-12 11:28:02 +03:00
|
|
|
|
|
|
|
|
|
|
|
def update_port_pci_info(pod, vif):
|
|
|
|
node = get_host_id(pod)
|
|
|
|
annot_port_pci_info = get_port_annot_pci_info(node, vif.id)
|
2020-01-27 11:48:16 +01:00
|
|
|
os_net = clients.get_network_client()
|
2019-03-12 11:28:02 +03:00
|
|
|
LOG.debug("Neutron port %s is updated with binding:profile info %s",
|
|
|
|
vif.id, annot_port_pci_info)
|
2020-01-27 11:48:16 +01:00
|
|
|
os_net.update_port(vif.id, binding_profile=annot_port_pci_info)
|
2019-03-12 11:28:02 +03:00
|
|
|
|
|
|
|
|
|
|
|
def get_port_annot_pci_info(nodename, neutron_port):
|
|
|
|
k8s = clients.get_kubernetes_client()
|
|
|
|
annot_name = constants.K8S_ANNOTATION_NODE_PCI_DEVICE_INFO
|
|
|
|
annot_name = annot_name + '-' + neutron_port
|
|
|
|
|
|
|
|
node_info = k8s.get('/api/v1/nodes/{}'.format(nodename))
|
|
|
|
annotations = node_info['metadata']['annotations']
|
|
|
|
try:
|
|
|
|
json_pci_info = annotations[annot_name]
|
|
|
|
pci_info = jsonutils.loads(json_pci_info)
|
|
|
|
except KeyError:
|
|
|
|
pci_info = {}
|
|
|
|
except Exception:
|
|
|
|
LOG.exception('Exception when reading annotations '
|
|
|
|
'%s and converting from json', annot_name)
|
|
|
|
return pci_info
|