summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerzySzachniewicz <jerzy.szachniewicz@nokia.com>2020-12-09 10:11:07 +0100
committerJerzy Szachniewicz <jerzy.szachniewicz@nokia.com>2020-12-10 09:44:35 +0000
commit4b5b14368861b9ca468d79326fabcd2992afb3d0 (patch)
treef4542b4afac5c16828409e59a51b7d0e01dc61c5
parent918f38777a822f764818e1fac3bb9d7e0ea2884a (diff)
Add option to use services with ipv6
Issue-ID: DCAEGEN2-2388 Signed-off-by: JerzySzachniewicz <jerzy.szachniewicz@nokia.com> Change-Id: I34ca694b38e9c3121ec7a0bd95c92071392052d3 Signed-off-by: JerzySzachniewicz <jerzy.szachniewicz@nokia.com>
-rw-r--r--k8s/ChangeLog.md4
-rw-r--r--k8s/README.md11
-rw-r--r--k8s/k8sclient/k8sclient.py58
-rw-r--r--k8s/k8splugin_types.yaml2
-rw-r--r--k8s/plugin_testing_blueprints/blueprints/nginx-svc-nodeport-ipv6.yaml25
-rw-r--r--k8s/pom.xml2
-rw-r--r--k8s/setup.py2
-rw-r--r--k8s/tests/test_k8sclient.py44
-rw-r--r--k8s/tests/test_tasks.py8
9 files changed, 114 insertions, 42 deletions
diff --git a/k8s/ChangeLog.md b/k8s/ChangeLog.md
index ac7b0d5..908be27 100644
--- a/k8s/ChangeLog.md
+++ b/k8s/ChangeLog.md
@@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
-
+## [3.5.1]
+* DCAEGEN2-2388 - Extend DCAE CFY K8S plugin to support IPv6 services.
+* Add properties to ports list to support IPv6 services
## [3.5.0]
* DCAEGEN2-2388 - Extend DCAE CFY K8S plugin to support IPv6 services.
* Update kubernetes python plugin to version 12.0.1
diff --git a/k8s/README.md b/k8s/README.md
index e310dee..db97040 100644
--- a/k8s/README.md
+++ b/k8s/README.md
@@ -136,6 +136,17 @@ setting the `<host port>` to 0 will expose the `<container port>` to other compo
ports on the Kubernetes host's external interface. Setting `<host port>` to a non-zero value will expose that port on the external interfaces
of every Kubernetes host in the cluster. (This uses the Kubernetes `NodePort` service type.)
+In dualstack Kubernetes environment, adding parameter ipv6 or ipv4, specify which ip family will be used.
+If ipv6 will be set in only ipv4 Kubernetes cluster, service will use ipv4 instead of declared ipv6.
+
+```yaml
+ports:
+ - concat: ['8000:31000']
+ ipv6: false
+ - concat: ['8000:31001']
+ ipv6: true
+```
+
#### `max_wait`
Integer - seconds to wait for component to become ready before throwing a `NonRecoverableError`. For example:
diff --git a/k8s/k8sclient/k8sclient.py b/k8s/k8sclient/k8sclient.py
index cd17999..401871f 100644
--- a/k8s/k8sclient/k8sclient.py
+++ b/k8s/k8sclient/k8sclient.py
@@ -59,6 +59,9 @@ def _create_service_name(component_name):
def _create_exposed_service_name(component_name):
return ("x{0}".format(component_name))[:63]
+def _create_exposed_v6_service_name(component_name):
+ return ("x{0}-ipv6".format(component_name))[:63]
+
def _configure_api(location=None):
# Look for a kubernetes config file
if os.path.exists(K8S_CONFIG_PATH):
@@ -223,11 +226,13 @@ def _create_deployment_object(component_name,
return deployment
-def _create_service_object(service_name, component_name, service_ports, annotations, labels, service_type):
+
+def _create_service_object(service_name, component_name, service_ports, annotations, labels, service_type, ip_family):
service_spec = client.V1ServiceSpec(
ports=service_ports,
- selector={"app" : component_name},
- type=service_type
+ selector={"app": component_name},
+ type=service_type,
+ ip_family=ip_family
)
if annotations:
metadata = client.V1ObjectMeta(name=_create_service_name(service_name), labels=labels, annotations=annotations)
@@ -250,21 +255,28 @@ def parse_ports(port_list):
container_ports = []
port_map = {}
for p in port_list:
+ ipv6 = False
+ if type(p) is dict:
+ ipv6 = "ipv6" in p and p['ipv6']
+ p = "".join(str(v) for v in p['concat'])
m = PORTS.match(p.strip())
if m:
cport = int(m.group(1))
- hport = int (m.group(4))
+ hport = int(m.group(4))
if m.group(3):
proto = (m.group(3)).upper()
else:
proto = "TCP"
- container_ports.append((cport, proto))
- port_map[(cport, proto)] = hport
+ port = (cport, proto)
+ if port not in container_ports:
+ container_ports.append(port)
+ port_map[(cport, proto, ipv6)] = hport
else:
raise ValueError("Bad port specification: {0}".format(p))
return container_ports, port_map
+
def _parse_volumes(volume_list):
volumes = []
volume_mounts = []
@@ -427,17 +439,24 @@ def _get_keystore_destination_paths(output_type, tls_cert_dir):
}[output_type]
return destination_paths_template.format(tls_cert_dir)
+
def _process_port_map(port_map):
- service_ports = [] # Ports exposed internally on the k8s network
- exposed_ports = [] # Ports to be mapped to ports on the k8s nodes via NodePort
- for (cport, proto), hport in port_map.items():
+ service_ports = [] # Ports exposed internally on the k8s network
+ exposed_ports = [] # Ports to be mapped to ports on the k8s nodes via NodePort
+ exposed_ports_ipv6 = []
+ for (cport, proto, ipv6), hport in port_map.items():
name = "xport-{0}-{1}".format(proto[0].lower(), cport)
cport = int(cport)
hport = int(hport)
- service_ports.append(client.V1ServicePort(port=cport, protocol=proto, name=name[1:]))
+ port = client.V1ServicePort(port=cport, protocol=proto, name=name[1:])
+ if port not in service_ports:
+ service_ports.append(port)
if hport != 0:
- exposed_ports.append(client.V1ServicePort(port=cport, protocol=proto, node_port=hport, name=name))
- return service_ports, exposed_ports
+ if ipv6:
+ exposed_ports_ipv6.append(client.V1ServicePort(port=cport, protocol=proto, node_port=hport, name=name))
+ else:
+ exposed_ports.append(client.V1ServicePort(port=cport, protocol=proto, node_port=hport, name=name))
+ return service_ports, exposed_ports, exposed_ports_ipv6
def _service_exists(location, namespace, component_name):
exists = False
@@ -644,10 +663,11 @@ def deploy(ctx, namespace, component_name, image, replicas, always_pull, k8sconf
# Create service(s), if a port mapping is specified
if port_map:
- service_ports, exposed_ports = _process_port_map(port_map)
+ service_ports, exposed_ports, exposed_ports_ipv6 = _process_port_map(port_map)
# Create a ClusterIP service for access via the k8s network
- service = _create_service_object(_create_service_name(component_name), component_name, service_ports, None, labels, "ClusterIP")
+ service = _create_service_object(_create_service_name(component_name), component_name, service_ports, None,
+ labels, "ClusterIP", "IPv4")
core.create_namespaced_service(namespace, service)
cip_service_created = True
deployment_description["services"].append(_create_service_name(component_name))
@@ -655,10 +675,18 @@ def deploy(ctx, namespace, component_name, image, replicas, always_pull, k8sconf
# If there are ports to be exposed on the k8s nodes, create a "NodePort" service
if exposed_ports:
exposed_service = \
- _create_service_object(_create_exposed_service_name(component_name), component_name, exposed_ports, '', labels, "NodePort")
+ _create_service_object(_create_exposed_service_name(component_name), component_name, exposed_ports,
+ '', labels, "NodePort", "IPv4")
core.create_namespaced_service(namespace, exposed_service)
deployment_description["services"].append(_create_exposed_service_name(component_name))
+ if exposed_ports_ipv6:
+ exposed_service_ipv6 = \
+ _create_service_object(_create_exposed_v6_service_name(component_name), component_name,
+ exposed_ports_ipv6, '', labels, "NodePort", "IPv6")
+ core.create_namespaced_service(namespace, exposed_service_ipv6)
+ deployment_description["services"].append(_create_exposed_v6_service_name(component_name))
+
except Exception as e:
# If the ClusterIP service was created, delete the service:
if cip_service_created:
diff --git a/k8s/k8splugin_types.yaml b/k8s/k8splugin_types.yaml
index 1feb275..666d0ba 100644
--- a/k8s/k8splugin_types.yaml
+++ b/k8s/k8splugin_types.yaml
@@ -24,7 +24,7 @@ plugins:
k8s:
executor: 'central_deployment_agent'
package_name: k8splugin
- package_version: 3.5.0
+ package_version: 3.5.1
data_types:
diff --git a/k8s/plugin_testing_blueprints/blueprints/nginx-svc-nodeport-ipv6.yaml b/k8s/plugin_testing_blueprints/blueprints/nginx-svc-nodeport-ipv6.yaml
new file mode 100644
index 0000000..a356daf
--- /dev/null
+++ b/k8s/plugin_testing_blueprints/blueprints/nginx-svc-nodeport-ipv6.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+description: >
+ Simple blueprint to launch nginx as a "service component"
+ Exposes port as a NodePort service with ipv6
+ If kubernetes doesn't have ipv6, service will get ipv4
+
+imports:
+ - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml
+ - plugin:k8splugin?version=>=3.0.0,<4.0.0
+
+node_templates:
+ web_server:
+ type: dcae.nodes.ContainerizedServiceComponent
+ properties:
+ service_component_type: 'nginx-web'
+ image: nginx
+ docker_config:
+ healthcheck:
+ type: "http"
+ endpoint: "/"
+ ports:
+ - '80:0'
+ - concat: ['80:30581']
+ ipv6: true
diff --git a/k8s/pom.xml b/k8s/pom.xml
index 0b77016..80e84b7 100644
--- a/k8s/pom.xml
+++ b/k8s/pom.xml
@@ -29,7 +29,7 @@ limitations under the License.
<groupId>org.onap.dcaegen2.platform.plugins</groupId>
<artifactId>k8s</artifactId>
<name>k8s-plugin</name>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.1-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/k8s/setup.py b/k8s/setup.py
index e708ab1..9d813f2 100644
--- a/k8s/setup.py
+++ b/k8s/setup.py
@@ -24,7 +24,7 @@ from setuptools import setup
setup(
name='k8splugin',
description='Cloudify plugin for containerized components deployed using Kubernetes',
- version="3.5.0",
+ version="3.5.1",
author='J. F. Lucas, Michael Hwang, Tommy Carpenter, Joanna Jeremicz, Sylwia Jakubek, Jan Malkiewicz, Remigiusz Janeczek, Piotr Marcinkiewicz',
packages=['k8splugin','k8sclient','configure'],
zip_safe=False,
diff --git a/k8s/tests/test_k8sclient.py b/k8s/tests/test_k8sclient.py
index 4f669d8..9e5bcb9 100644
--- a/k8s/tests/test_k8sclient.py
+++ b/k8s/tests/test_k8sclient.py
@@ -93,16 +93,18 @@ def test_parse_ports():
good_ports = [{"in": input, "ex": expected}
for (input, expected) in [
- ("9101:0", (9101, 0, "TCP")),
- ("9101/TCP:0", (9101, 0, "TCP")),
- ("9101/tcp:0", (9101, 0, "TCP")),
- ("9101/UDP:0", (9101, 0, "UDP")),
- ("9101/udp:0", (9101, 0, "UDP")),
- ("9101:31043", (9101, 31043, "TCP")),
- ("9101/TCP:31043", (9101, 31043, "TCP")),
- ("9101/tcp:31043", (9101, 31043, "TCP")),
- ("9101/UDP:31043", (9101, 31043, "UDP")),
- ("9101/udp:31043", (9101, 31043, "UDP"))
+ ({u'concat': [u'9101', u':', 0], u'ipv6': True}, (9101, 0, True, "TCP")),
+ ({u'concat': [u'9102', u':', 0], u'ipv6': False}, (9102, 0, False, "TCP")),
+ ({u'concat': [u'9103', u':', 36000], u'ipv6': True}, (9103, 36000, True, "TCP")),
+ ("9101/TCP:0", (9101, 0, False, "TCP")),
+ ("9101/tcp:0", (9101, 0, False, "TCP")),
+ ("9101/UDP:0", (9101, 0, False, "UDP")),
+ ("9101/udp:0", (9101, 0, False, "UDP")),
+ ("9101:31043", (9101, 31043, False, "TCP")),
+ ("9101/TCP:31043", (9101, 31043, False, "TCP")),
+ ("9101/tcp:31043", (9101, 31043, False, "TCP")),
+ ("9101/UDP:31043", (9101, 31043, False, "UDP")),
+ ("9101/udp:31043", (9101, 31043, False, "UDP"))
]
]
@@ -118,7 +120,9 @@ def test_parse_ports():
]
port_list = [
- "9101:0",
+ {u'concat': [u'9101', u':', 3023], u'ipv6': True},
+ {u'concat': [u'9102', u':', 0], u'ipv6': True},
+ {u'concat': [u'9103', u':', 0], u'ipv6': False},
"5053/tcp:5053",
"5053/udp:5053",
"9661:19661",
@@ -127,19 +131,21 @@ def test_parse_ports():
]
expected_port_map = {
- (9101,"TCP") : 0,
- (5053,"TCP") : 5053,
- (5053,"UDP") : 5053,
- (9661,"TCP") : 19661,
- (9661,"UDP") : 19661,
- (8080,"TCP") : 8080
+ (9101, "TCP", True): 3023,
+ (9102, "TCP", True): 0,
+ (9103, "TCP", False): 0,
+ (5053, "TCP", False): 5053,
+ (5053, "UDP", False): 5053,
+ (9661, "TCP", False): 19661,
+ (9661, "UDP", False): 19661,
+ (8080, "TCP", False): 8080
}
for test_case in good_ports:
container_ports, port_map = parse_ports([test_case["in"]])
- (cport, hport, proto) = test_case["ex"]
+ (cport, hport, ipv6, proto) = test_case["ex"]
assert container_ports == [(cport, proto)]
- assert port_map == {(cport, proto) : hport}
+ assert port_map == {(cport, proto, ipv6): hport}
for port in bad_ports:
with pytest.raises(ValueError):
diff --git a/k8s/tests/test_tasks.py b/k8s/tests/test_tasks.py
index b82a4ae..50a3325 100644
--- a/k8s/tests/test_tasks.py
+++ b/k8s/tests/test_tasks.py
@@ -149,15 +149,15 @@ def test_enhance_docker_params(mockconfig):
# Good - Test just docker config ports and volumes
- test_kwargs = { "docker_config": { "ports": ["1:1", "2:2"],
+ test_kwargs = { "docker_config": { "ports": [{u'concat': [u'8080', u':', 0], u'ipv6': True}, "1:1"],
"volumes": [{"container": "somewhere", "host": "somewhere else"}] },
"service_id": None }
actual = tasks._enhance_docker_params(**test_kwargs)
- assert actual == {'envs': {}, 'docker_config': {'ports': ['1:1', '2:2'],
+ assert actual == {'envs': {}, 'docker_config': {'ports': [{u'concat': [u'8080', u':', 0], u'ipv6': True}, "1:1"],
'volumes': [{'host': 'somewhere else', 'container': 'somewhere'}]},
- 'ports': ['1:1', '2:2'], 'volumes': [{'host': 'somewhere else',
- 'container': 'somewhere'}], "service_id": None}
+ 'ports': [{u'concat': [u'8080', u':', 0], u'ipv6': True}, "1:1"], 'volumes': [{'host': 'somewhere else',
+ 'container': 'somewhere'}], "service_id": None}
# Good - Test just docker config ports and volumes with overrrides