Allow k8s cluster without LBaaS
This patch adds an environment file and a couple of template resources to allow the LBaaS resources to be conditionally enabled/disabled. Change-Id: I40ef0839dca84f398efb02022fa7c1de821fb1a3 Partially-Implements: blueprint decouple-lbaas Partially-Implements: blueprint bay-with-no-floating-ips
This commit is contained in:
parent
cb99c64614
commit
2ea72d739d
@ -164,6 +164,12 @@ def validate_os_resources(context, baymodel):
|
|||||||
validate_method(baymodel[attr])
|
validate_method(baymodel[attr])
|
||||||
|
|
||||||
|
|
||||||
|
def validate_master_count(bay, baymodel):
|
||||||
|
if bay['master_count'] > 1 and not baymodel['master_lb_enabled']:
|
||||||
|
raise exception.InvalidParameterValue(_(
|
||||||
|
"master_count must be 1 when master_lb_enabled is False"))
|
||||||
|
|
||||||
|
|
||||||
# Dictionary that maintains a list of validation functions
|
# Dictionary that maintains a list of validation functions
|
||||||
validators = {'image_id': validate_image,
|
validators = {'image_id': validate_image,
|
||||||
'flavor_id': validate_flavor,
|
'flavor_id': validate_flavor,
|
||||||
|
@ -329,6 +329,7 @@ class BaysController(rest.RestController):
|
|||||||
action='bay:create')
|
action='bay:create')
|
||||||
baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id)
|
baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id)
|
||||||
attr_validator.validate_os_resources(context, baymodel.as_dict())
|
attr_validator.validate_os_resources(context, baymodel.as_dict())
|
||||||
|
attr_validator.validate_master_count(bay.as_dict(), baymodel.as_dict())
|
||||||
bay_dict = bay.as_dict()
|
bay_dict = bay.as_dict()
|
||||||
bay_dict['project_id'] = context.project_id
|
bay_dict['project_id'] = context.project_id
|
||||||
bay_dict['user_id'] = context.user_id
|
bay_dict['user_id'] = context.user_id
|
||||||
|
@ -161,6 +161,12 @@ class K8sTemplateDefinition(template_def.BaseTemplateDefinition):
|
|||||||
extra_params=extra_params,
|
extra_params=extra_params,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
def get_env_files(self, baymodel):
|
||||||
|
if baymodel.master_lb_enabled:
|
||||||
|
return ['environments/with_master_lb.yaml']
|
||||||
|
else:
|
||||||
|
return ['environments/no_master_lb.yaml']
|
||||||
|
|
||||||
|
|
||||||
class AtomicK8sTemplateDefinition(K8sTemplateDefinition):
|
class AtomicK8sTemplateDefinition(K8sTemplateDefinition):
|
||||||
"""Kubernetes template for a Fedora Atomic VM."""
|
"""Kubernetes template for a Fedora Atomic VM."""
|
||||||
|
12
magnum/templates/kubernetes/environments/no_master_lb.yaml
Normal file
12
magnum/templates/kubernetes/environments/no_master_lb.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Environment file to disable LBaaS in a Kubernetes cluster by mapping
|
||||||
|
# LBaaS-related resource types to OS::Heat::None
|
||||||
|
resource_registry:
|
||||||
|
"Magnum::ApiGatewaySwitcher": ../fragments/api_gateway_switcher_master.yaml
|
||||||
|
|
||||||
|
# kubecluster.yaml
|
||||||
|
"Magnum::Optional::Neutron::Pool": "OS::Heat::None"
|
||||||
|
"Magnum::Optional::Neutron::Pool::FloatingIP": "OS::Heat::None"
|
||||||
|
"Magnum::Optional::Neutron::Pool::HealthMonitor": "OS::Heat::None"
|
||||||
|
|
||||||
|
# kubemaster.yaml
|
||||||
|
"Magnum::Optional::Neutron::PoolMember": "OS::Heat::None"
|
12
magnum/templates/kubernetes/environments/with_master_lb.yaml
Normal file
12
magnum/templates/kubernetes/environments/with_master_lb.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Environment file to enable LBaaS in a Kubernetes cluster by mapping
|
||||||
|
# LBaaS-related resource types to the real LBaaS resource types.
|
||||||
|
resource_registry:
|
||||||
|
"Magnum::ApiGatewaySwitcher": ../fragments/api_gateway_switcher_pool.yaml
|
||||||
|
|
||||||
|
# kubecluster.yaml
|
||||||
|
"Magnum::Optional::Neutron::Pool": "OS::Neutron::Pool"
|
||||||
|
"Magnum::Optional::Neutron::Pool::FloatingIP": "OS::Neutron::FloatingIP"
|
||||||
|
"Magnum::Optional::Neutron::Pool::HealthMonitor": "OS::Neutron::HealthMonitor"
|
||||||
|
|
||||||
|
# kubemaster.yaml
|
||||||
|
"Magnum::Optional::Neutron::PoolMember": "OS::Neutron::PoolMember"
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
|
||||||
|
description: >
|
||||||
|
This is a template resource that accepts public and private IPs from both
|
||||||
|
a Neutron LBaaS Pool and a master node. It connects the master inputs
|
||||||
|
to its outputs, essentially acting as one state of a multiplexer.
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
pool_public_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
pool_private_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
master_public_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
master_private_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
|
||||||
|
public_ip:
|
||||||
|
value: {get_param: master_public_ip}
|
||||||
|
|
||||||
|
private_ip:
|
||||||
|
value: {get_param: master_private_ip}
|
@ -0,0 +1,32 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
|
||||||
|
description: >
|
||||||
|
This is a template resource that accepts public and private IPs from both
|
||||||
|
a Neutron LBaaS Pool and a master node. It connects the pool inputs
|
||||||
|
to its outputs, essentially acting as one state of a multiplexer.
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
pool_public_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
pool_private_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
master_public_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
master_private_ip:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
|
||||||
|
public_ip:
|
||||||
|
value: {get_param: pool_public_ip}
|
||||||
|
|
||||||
|
private_ip:
|
||||||
|
value: {get_param: pool_private_ip}
|
@ -350,7 +350,7 @@ resources:
|
|||||||
#
|
#
|
||||||
|
|
||||||
api_monitor:
|
api_monitor:
|
||||||
type: OS::Neutron::HealthMonitor
|
type: Magnum::Optional::Neutron::Pool::HealthMonitor
|
||||||
properties:
|
properties:
|
||||||
type: TCP
|
type: TCP
|
||||||
delay: 5
|
delay: 5
|
||||||
@ -358,7 +358,7 @@ resources:
|
|||||||
timeout: 5
|
timeout: 5
|
||||||
|
|
||||||
api_pool:
|
api_pool:
|
||||||
type: OS::Neutron::Pool
|
type: Magnum::Optional::Neutron::Pool
|
||||||
properties:
|
properties:
|
||||||
protocol: {get_param: loadbalancing_protocol}
|
protocol: {get_param: loadbalancing_protocol}
|
||||||
monitors: [{get_resource: api_monitor}]
|
monitors: [{get_resource: api_monitor}]
|
||||||
@ -368,7 +368,7 @@ resources:
|
|||||||
protocol_port: {get_param: kubernetes_port}
|
protocol_port: {get_param: kubernetes_port}
|
||||||
|
|
||||||
api_pool_floating:
|
api_pool_floating:
|
||||||
type: OS::Neutron::FloatingIP
|
type: Magnum::Optional::Neutron::Pool::FloatingIP
|
||||||
depends_on:
|
depends_on:
|
||||||
- extrouter_inside
|
- extrouter_inside
|
||||||
properties:
|
properties:
|
||||||
@ -376,7 +376,7 @@ resources:
|
|||||||
port_id: {get_attr: [api_pool, vip, port_id]}
|
port_id: {get_attr: [api_pool, vip, port_id]}
|
||||||
|
|
||||||
etcd_monitor:
|
etcd_monitor:
|
||||||
type: OS::Neutron::HealthMonitor
|
type: Magnum::Optional::Neutron::Pool::HealthMonitor
|
||||||
properties:
|
properties:
|
||||||
type: TCP
|
type: TCP
|
||||||
delay: 5
|
delay: 5
|
||||||
@ -384,7 +384,7 @@ resources:
|
|||||||
timeout: 5
|
timeout: 5
|
||||||
|
|
||||||
etcd_pool:
|
etcd_pool:
|
||||||
type: OS::Neutron::Pool
|
type: Magnum::Optional::Neutron::Pool
|
||||||
properties:
|
properties:
|
||||||
protocol: HTTP
|
protocol: HTTP
|
||||||
monitors: [{get_resource: etcd_monitor}]
|
monitors: [{get_resource: etcd_monitor}]
|
||||||
@ -393,6 +393,26 @@ resources:
|
|||||||
vip:
|
vip:
|
||||||
protocol_port: 2379
|
protocol_port: 2379
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
#
|
||||||
|
# resources that expose the IPs of either the kube master or a given
|
||||||
|
# LBaaS pool depending on whether LBaaS is enabled for the bay.
|
||||||
|
#
|
||||||
|
|
||||||
|
api_address_switch:
|
||||||
|
type: Magnum::ApiGatewaySwitcher
|
||||||
|
properties:
|
||||||
|
pool_public_ip: {get_attr: [api_pool_floating, floating_ip_address]}
|
||||||
|
pool_private_ip: {get_attr: [api_pool, vip, address]}
|
||||||
|
master_public_ip: {get_attr: [kube_masters, resource.0.kube_master_external_ip]}
|
||||||
|
master_private_ip: {get_attr: [kube_masters, resource.0.kube_master_ip]}
|
||||||
|
|
||||||
|
etcd_address_switch:
|
||||||
|
type: Magnum::ApiGatewaySwitcher
|
||||||
|
properties:
|
||||||
|
pool_private_ip: {get_attr: [etcd_pool, vip, address]}
|
||||||
|
master_private_ip: {get_attr: [kube_masters, resource.0.kube_master_ip]}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
#
|
#
|
||||||
# kubernetes masters. This is a resource group that will create
|
# kubernetes masters. This is a resource group that will create
|
||||||
@ -470,8 +490,8 @@ resources:
|
|||||||
fixed_subnet: {get_resource: fixed_subnet}
|
fixed_subnet: {get_resource: fixed_subnet}
|
||||||
network_driver: {get_param: network_driver}
|
network_driver: {get_param: network_driver}
|
||||||
flannel_network_cidr: {get_param: flannel_network_cidr}
|
flannel_network_cidr: {get_param: flannel_network_cidr}
|
||||||
kube_master_ip: {get_attr: [api_pool, vip, address]}
|
kube_master_ip: {get_attr: [api_address_switch, private_ip]}
|
||||||
etcd_server_ip: {get_attr: [etcd_pool, vip, address]}
|
etcd_server_ip: {get_attr: [etcd_address_switch, private_ip]}
|
||||||
external_network: {get_param: external_network}
|
external_network: {get_param: external_network}
|
||||||
kube_allow_priv: {get_param: kube_allow_priv}
|
kube_allow_priv: {get_param: kube_allow_priv}
|
||||||
docker_volume_size: {get_param: docker_volume_size}
|
docker_volume_size: {get_param: docker_volume_size}
|
||||||
@ -513,7 +533,7 @@ outputs:
|
|||||||
str_replace:
|
str_replace:
|
||||||
template: api_ip_address
|
template: api_ip_address
|
||||||
params:
|
params:
|
||||||
api_ip_address: {get_attr: [api_pool_floating, floating_ip_address]}
|
api_ip_address: {get_attr: [api_address_switch, public_ip]}
|
||||||
description: >
|
description: >
|
||||||
This is the API endpoint of the Kubernetes server. Use this to access
|
This is the API endpoint of the Kubernetes server. Use this to access
|
||||||
the Kubernetes API from outside the cluster.
|
the Kubernetes API from outside the cluster.
|
||||||
|
@ -89,10 +89,12 @@ parameters:
|
|||||||
api_public_address:
|
api_public_address:
|
||||||
type: string
|
type: string
|
||||||
description: Public IP address of the Kubernetes master server.
|
description: Public IP address of the Kubernetes master server.
|
||||||
|
default: ""
|
||||||
|
|
||||||
api_private_address:
|
api_private_address:
|
||||||
type: string
|
type: string
|
||||||
description: Private IP address of the Kubernetes master server.
|
description: Private IP address of the Kubernetes master server.
|
||||||
|
default: ""
|
||||||
|
|
||||||
fixed_network:
|
fixed_network:
|
||||||
type: string
|
type: string
|
||||||
@ -193,6 +195,20 @@ resources:
|
|||||||
handle: {get_resource: master_wait_handle}
|
handle: {get_resource: master_wait_handle}
|
||||||
timeout: {get_param: wait_condition_timeout}
|
timeout: {get_param: wait_condition_timeout}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
#
|
||||||
|
# resource that exposes the IPs of either the kube master or the API
|
||||||
|
# LBaaS pool depending on whether LBaaS is enabled for the bay.
|
||||||
|
#
|
||||||
|
|
||||||
|
api_address_switch:
|
||||||
|
type: Magnum::ApiGatewaySwitcher
|
||||||
|
properties:
|
||||||
|
pool_public_ip: {get_param: api_public_address}
|
||||||
|
pool_private_ip: {get_param: api_private_address}
|
||||||
|
master_public_ip: {get_attr: [kube_master_floating, floating_ip_address]}
|
||||||
|
master_private_ip: {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
#
|
#
|
||||||
# software configs. these are components that are combined into
|
# software configs. these are components that are combined into
|
||||||
@ -207,8 +223,8 @@ resources:
|
|||||||
str_replace:
|
str_replace:
|
||||||
template: {get_file: fragments/write-heat-params-master.yaml}
|
template: {get_file: fragments/write-heat-params-master.yaml}
|
||||||
params:
|
params:
|
||||||
"$KUBE_API_PUBLIC_ADDRESS": {get_param: api_public_address}
|
"$KUBE_API_PUBLIC_ADDRESS": {get_attr: [api_address_switch, public_ip]}
|
||||||
"$KUBE_API_PRIVATE_ADDRESS": {get_param: api_private_address}
|
"$KUBE_API_PRIVATE_ADDRESS": {get_attr: [api_address_switch, private_ip]}
|
||||||
"$KUBE_API_PORT": {get_param: kubernetes_port}
|
"$KUBE_API_PORT": {get_param: kubernetes_port}
|
||||||
"$KUBE_NODE_IP": {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
"$KUBE_NODE_IP": {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
||||||
"$KUBE_ALLOW_PRIV": {get_param: kube_allow_priv}
|
"$KUBE_ALLOW_PRIV": {get_param: kube_allow_priv}
|
||||||
@ -410,14 +426,14 @@ resources:
|
|||||||
port_id: {get_resource: kube_master_eth0}
|
port_id: {get_resource: kube_master_eth0}
|
||||||
|
|
||||||
api_pool_member:
|
api_pool_member:
|
||||||
type: OS::Neutron::PoolMember
|
type: Magnum::Optional::Neutron::PoolMember
|
||||||
properties:
|
properties:
|
||||||
pool_id: {get_param: api_pool_id}
|
pool_id: {get_param: api_pool_id}
|
||||||
address: {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
address: {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
||||||
protocol_port: {get_param: kubernetes_port}
|
protocol_port: {get_param: kubernetes_port}
|
||||||
|
|
||||||
etcd_pool_member:
|
etcd_pool_member:
|
||||||
type: OS::Neutron::PoolMember
|
type: Magnum::Optional::Neutron::PoolMember
|
||||||
properties:
|
properties:
|
||||||
pool_id: {get_param: etcd_pool_id}
|
pool_id: {get_param: etcd_pool_id}
|
||||||
address: {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
address: {get_attr: [kube_master_eth0, fixed_ips, 0, ip_address]}
|
||||||
|
@ -640,6 +640,24 @@ class TestPost(api_base.FunctionalTest):
|
|||||||
self.assertTrue(self.mock_valid_os_res.called)
|
self.assertTrue(self.mock_valid_os_res.called)
|
||||||
self.assertEqual(400, response.status_int)
|
self.assertEqual(400, response.status_int)
|
||||||
|
|
||||||
|
def test_create_bay_with_no_lb_one_node(self):
|
||||||
|
baymodel = obj_utils.create_test_baymodel(
|
||||||
|
self.context, name='foo', uuid='foo', master_lb_enabled=False)
|
||||||
|
bdict = apiutils.bay_post_data(baymodel_id=baymodel.name,
|
||||||
|
master_count=1)
|
||||||
|
response = self.post_json('/bays', bdict, expect_errors=True)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
self.assertEqual(201, response.status_int)
|
||||||
|
|
||||||
|
def test_create_bay_with_no_lb_multi_node(self):
|
||||||
|
baymodel = obj_utils.create_test_baymodel(
|
||||||
|
self.context, name='foo', uuid='foo', master_lb_enabled=False)
|
||||||
|
bdict = apiutils.bay_post_data(baymodel_id=baymodel.name,
|
||||||
|
master_count=3)
|
||||||
|
response = self.post_json('/bays', bdict, expect_errors=True)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
self.assertEqual(400, response.status_int)
|
||||||
|
|
||||||
|
|
||||||
class TestDelete(api_base.FunctionalTest):
|
class TestDelete(api_base.FunctionalTest):
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
'server_type': 'vm',
|
'server_type': 'vm',
|
||||||
'registry_enabled': False,
|
'registry_enabled': False,
|
||||||
'insecure_registry': '10.0.0.1:5000',
|
'insecure_registry': '10.0.0.1:5000',
|
||||||
|
'master_lb_enabled': False,
|
||||||
}
|
}
|
||||||
self.bay_dict = {
|
self.bay_dict = {
|
||||||
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
||||||
@ -176,7 +177,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
expected.pop(mapping[missing_attr], None)
|
expected.pop(mapping[missing_attr], None)
|
||||||
|
|
||||||
self.assertEqual(expected, definition)
|
self.assertEqual(expected, definition)
|
||||||
self.assertEqual([], env_files)
|
self.assertEqual(['environments/no_master_lb.yaml'], env_files)
|
||||||
|
|
||||||
@patch('requests.get')
|
@patch('requests.get')
|
||||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
@ -242,7 +243,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.assertEqual(expected, definition)
|
self.assertEqual(expected, definition)
|
||||||
self.assertEqual([], env_files)
|
self.assertEqual(['environments/no_master_lb.yaml'], env_files)
|
||||||
|
|
||||||
@patch('requests.get')
|
@patch('requests.get')
|
||||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
@ -296,7 +297,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
'insecure_registry_url': '10.0.0.1:5000',
|
'insecure_registry_url': '10.0.0.1:5000',
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, definition)
|
self.assertEqual(expected, definition)
|
||||||
self.assertEqual([], env_files)
|
self.assertEqual(['environments/no_master_lb.yaml'], env_files)
|
||||||
|
|
||||||
@patch('requests.get')
|
@patch('requests.get')
|
||||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
@ -348,7 +349,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
'insecure_registry_url': '10.0.0.1:5000',
|
'insecure_registry_url': '10.0.0.1:5000',
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, definition)
|
self.assertEqual(expected, definition)
|
||||||
self.assertEqual([], env_files)
|
self.assertEqual(['environments/no_master_lb.yaml'], env_files)
|
||||||
|
|
||||||
@patch('requests.get')
|
@patch('requests.get')
|
||||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
@ -508,7 +509,7 @@ class TestBayConductorWithK8s(base.TestCase):
|
|||||||
'insecure_registry_url': '10.0.0.1:5000',
|
'insecure_registry_url': '10.0.0.1:5000',
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, definition)
|
self.assertEqual(expected, definition)
|
||||||
self.assertEqual([], env_files)
|
self.assertEqual(['environments/no_master_lb.yaml'], env_files)
|
||||||
reqget.assert_called_once_with('http://etcd/test?size=1')
|
reqget.assert_called_once_with('http://etcd/test?size=1')
|
||||||
|
|
||||||
@patch('magnum.common.short_id.generate_id')
|
@patch('magnum.common.short_id.generate_id')
|
||||||
|
@ -53,7 +53,7 @@ def get_test_baymodel(**kw):
|
|||||||
'public': kw.get('public', False),
|
'public': kw.get('public', False),
|
||||||
'server_type': kw.get('server_type', 'vm'),
|
'server_type': kw.get('server_type', 'vm'),
|
||||||
'insecure_registry': kw.get('insecure_registry', '10.0.0.1:5000'),
|
'insecure_registry': kw.get('insecure_registry', '10.0.0.1:5000'),
|
||||||
'master_lb_enabled': kw.get('master_lb_enabled', False),
|
'master_lb_enabled': kw.get('master_lb_enabled', True),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user