Kubernetes integration with OpenStack networking
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

namespace_security_groups.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # Copyright (c) 2018 Red Hat, Inc.
  2. # All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # 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, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. from kuryr.lib._i18n import _
  16. from oslo_config import cfg
  17. from oslo_log import log as logging
  18. from kuryr_kubernetes import clients
  19. from kuryr_kubernetes import config
  20. from kuryr_kubernetes import constants
  21. from kuryr_kubernetes.controller.drivers import base
  22. from kuryr_kubernetes import exceptions
  23. from neutronclient.common import exceptions as n_exc
  24. LOG = logging.getLogger(__name__)
  25. namespace_sg_driver_opts = [
  26. cfg.StrOpt('sg_allow_from_namespaces',
  27. help=_("Default security group to allow traffic from the "
  28. "namespaces into the default namespace.")),
  29. cfg.StrOpt('sg_allow_from_default',
  30. help=_("Default security group to allow traffic from the "
  31. "default namespaces into the other namespaces."))
  32. ]
  33. cfg.CONF.register_opts(namespace_sg_driver_opts, "namespace_sg")
  34. DEFAULT_NAMESPACE = 'default'
  35. def _get_net_crd(namespace):
  36. kubernetes = clients.get_kubernetes_client()
  37. try:
  38. ns = kubernetes.get('%s/namespaces/%s' % (constants.K8S_API_BASE,
  39. namespace))
  40. except exceptions.K8sClientException:
  41. LOG.exception("Kubernetes Client Exception.")
  42. raise exceptions.ResourceNotReady(namespace)
  43. try:
  44. annotations = ns['metadata']['annotations']
  45. net_crd_name = annotations[constants.K8S_ANNOTATION_NET_CRD]
  46. except KeyError:
  47. LOG.exception("Namespace missing CRD annotations for selecting "
  48. "the corresponding security group.")
  49. raise exceptions.ResourceNotReady(namespace)
  50. try:
  51. net_crd = kubernetes.get('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
  52. net_crd_name))
  53. except exceptions.K8sClientException:
  54. LOG.exception("Kubernetes Client Exception.")
  55. raise
  56. return net_crd
  57. class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
  58. """Provides security groups for Pod based on a configuration option."""
  59. def get_security_groups(self, pod, project_id):
  60. namespace = pod['metadata']['namespace']
  61. net_crd = _get_net_crd(namespace)
  62. sg_list = [str(net_crd['spec']['sgId'])]
  63. extra_sgs = self._get_extra_sg(namespace)
  64. for sg in extra_sgs:
  65. sg_list.append(str(sg))
  66. sg_list.extend(config.CONF.neutron_defaults.pod_security_groups)
  67. return sg_list[:]
  68. def _get_extra_sg(self, namespace):
  69. # Differentiates between default namespace and the rest
  70. if namespace == DEFAULT_NAMESPACE:
  71. return [cfg.CONF.namespace_sg.sg_allow_from_namespaces]
  72. else:
  73. return [cfg.CONF.namespace_sg.sg_allow_from_default]
  74. def create_namespace_sg(self, namespace, project_id, crd_spec):
  75. neutron = clients.get_neutron_client()
  76. sg_name = "ns/" + namespace + "-sg"
  77. # create the associated SG for the namespace
  78. try:
  79. # default namespace is different from the rest
  80. # Default allows traffic from everywhere
  81. # The rest can be accessed from the default one
  82. sg = neutron.create_security_group(
  83. {
  84. "security_group": {
  85. "name": sg_name,
  86. "project_id": project_id
  87. }
  88. }).get('security_group')
  89. neutron.create_security_group_rule(
  90. {
  91. "security_group_rule": {
  92. "direction": "ingress",
  93. "remote_ip_prefix": crd_spec['subnetCIDR'],
  94. "security_group_id": sg['id']
  95. }
  96. })
  97. except n_exc.NeutronClientException as ex:
  98. LOG.error("Error creating security group for the namespace "
  99. "%s: %s", namespace, ex)
  100. raise ex
  101. return {'sgId': sg['id']}
  102. def delete_sg(self, sg_id):
  103. neutron = clients.get_neutron_client()
  104. try:
  105. neutron.delete_security_group(sg_id)
  106. except n_exc.NotFound:
  107. LOG.debug("Security Group not found: %s", sg_id)
  108. except n_exc.NeutronClientException:
  109. LOG.exception("Error deleting security group %s.", sg_id)
  110. raise
  111. def create_sg_rules(self, pod):
  112. LOG.debug("Security group driver does not create SG rules for "
  113. "the pods.")
  114. def delete_sg_rules(self, pod):
  115. LOG.debug("Security group driver does not delete SG rules for "
  116. "the pods.")
  117. def update_sg_rules(self, pod):
  118. LOG.debug("Security group driver does not update SG rules for "
  119. "the pods.")
  120. class NamespaceServiceSecurityGroupsDriver(base.ServiceSecurityGroupsDriver):
  121. """Provides security groups for Service based on a configuration option."""
  122. def get_security_groups(self, service, project_id):
  123. namespace = service['metadata']['namespace']
  124. net_crd = _get_net_crd(namespace)
  125. sg_list = []
  126. sg_list.append(str(net_crd['spec']['sgId']))
  127. extra_sgs = self._get_extra_sg(namespace)
  128. for sg in extra_sgs:
  129. sg_list.append(str(sg))
  130. return sg_list[:]
  131. def _get_extra_sg(self, namespace):
  132. # Differentiates between default namespace and the rest
  133. if namespace == DEFAULT_NAMESPACE:
  134. return [cfg.CONF.namespace_sg.sg_allow_from_default]
  135. else:
  136. return [cfg.CONF.namespace_sg.sg_allow_from_namespaces]