276 lines
11 KiB
Python
276 lines
11 KiB
Python
# 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.
|
|
|
|
import os
|
|
import random
|
|
import string
|
|
|
|
from oslo_log import log as logging
|
|
|
|
from senlin.common import context
|
|
from senlin.common import exception as exc
|
|
from senlin.objects import cluster as cluster_obj
|
|
from senlin.profiles.os.nova import server
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def GenKubeToken():
|
|
token_id = ''.join([random.choice(
|
|
string.digits + string.ascii_lowercase) for i in range(6)])
|
|
token_secret = ''.join([random.choice(
|
|
string.digits + string.ascii_lowercase) for i in range(16)])
|
|
token = '.'.join([token_id, token_secret])
|
|
return token
|
|
|
|
|
|
def loadScript(path):
|
|
script_file = os.path.join(os.path.dirname(__file__), path)
|
|
with open(script_file, "r") as f:
|
|
content = f.read()
|
|
return content
|
|
|
|
|
|
class KubeBaseProfile(server.ServerProfile):
|
|
"""Kubernetes Base Profile."""
|
|
|
|
def __init__(self, type_name, name, **kwargs):
|
|
super(KubeBaseProfile, self).__init__(type_name, name, **kwargs)
|
|
self.server_id = None
|
|
|
|
def _generate_kubeadm_token(self, obj):
|
|
token = GenKubeToken()
|
|
# store generated token
|
|
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
data = obj.data
|
|
data[self.KUBEADM_TOKEN] = token
|
|
cluster_obj.Cluster.update(ctx, obj.id, {'data': data})
|
|
return token
|
|
|
|
def _get_kubeadm_token(self, obj):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
return cluster.data.get(self.KUBEADM_TOKEN)
|
|
return None
|
|
|
|
def _update_master_ip(self, obj, ip):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
cluster.data['kube_master_ip'] = ip
|
|
cluster.update(ctx, obj.cluster_id, {'data': cluster.data})
|
|
|
|
def _create_network(self, obj):
|
|
client = self.network(obj)
|
|
try:
|
|
net = client.network_create()
|
|
subnet = client.subnet_create(network_id=net.id,
|
|
cidr='10.7.0.0/24',
|
|
ip_version=4)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceCreation(type='kubernetes',
|
|
message=str(ex),
|
|
resource_id=obj.id)
|
|
pub_net = client.network_get(self.properties[self.PUBLIC_NETWORK])
|
|
try:
|
|
router = client.router_create(
|
|
external_gateway_info={"network_id": pub_net.id})
|
|
client.add_interface_to_router(router, subnet_id=subnet.id)
|
|
fip = client.floatingip_create(floating_network_id=pub_net.id)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceCreation(type='kubernetes',
|
|
message=str(ex),
|
|
resource_id=obj.id)
|
|
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
data = obj.data
|
|
data[self.PRIVATE_NETWORK] = net.id
|
|
data[self.PRIVATE_SUBNET] = subnet.id
|
|
data[self.PRIVATE_ROUTER] = router.id
|
|
data[self.KUBE_MASTER_FLOATINGIP] = fip.floating_ip_address
|
|
data[self.KUBE_MASTER_FLOATINGIP_ID] = fip.id
|
|
|
|
cluster_obj.Cluster.update(ctx, obj.id, {'data': data})
|
|
|
|
return net.id
|
|
|
|
def _delete_network(self, obj):
|
|
client = self.network(obj)
|
|
fip_id = obj.data.get(self.KUBE_MASTER_FLOATINGIP_ID)
|
|
if fip_id:
|
|
try:
|
|
# delete floating ip
|
|
client.floatingip_delete(fip_id)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceDeletion(type='kubernetes', id=fip_id,
|
|
message=str(ex))
|
|
|
|
router = obj.data.get(self.PRIVATE_ROUTER)
|
|
subnet = obj.data.get(self.PRIVATE_SUBNET)
|
|
if router and subnet:
|
|
try:
|
|
client.remove_interface_from_router(router, subnet_id=subnet)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceDeletion(type='kubernetes',
|
|
id=subnet,
|
|
message=str(ex))
|
|
|
|
if router:
|
|
try:
|
|
# delete router
|
|
client.router_delete(router, ignore_missing=True)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceDeletion(type='kubernetes',
|
|
id=router,
|
|
message=str(ex))
|
|
|
|
net = obj.data.get(self.PRIVATE_NETWORK)
|
|
if net:
|
|
try:
|
|
# delete network
|
|
client.network_delete(net, ignore_missing=True)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceDeletion(type='kubernetes',
|
|
id=net,
|
|
message=str(ex))
|
|
|
|
def _associate_floatingip(self, obj, server):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
fip = cluster.data.get(self.KUBE_MASTER_FLOATINGIP)
|
|
if fip:
|
|
try:
|
|
self.compute(obj).server_floatingip_associate(server,
|
|
fip)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceOperation(op='floatingip',
|
|
type='kubernetes',
|
|
id=fip,
|
|
message=str(ex))
|
|
|
|
def _disassociate_floatingip(self, obj, server):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
fip = cluster.data.get(self.KUBE_MASTER_FLOATINGIP)
|
|
if fip:
|
|
try:
|
|
self.compute(obj).server_floatingip_disassociate(server,
|
|
fip)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceOperation(op='floatingip',
|
|
type='kubernetes',
|
|
id=fip,
|
|
message=str(ex))
|
|
|
|
def _get_cluster_data(self, obj):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
return cluster.data
|
|
return {}
|
|
|
|
def _get_network(self, obj):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
return cluster.data.get(self.PRIVATE_NETWORK)
|
|
return None
|
|
|
|
def _create_security_group(self, obj):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
sgid = obj.data.get(self.SECURITY_GROUP, None)
|
|
if sgid:
|
|
return sgid
|
|
|
|
client = self.network(obj)
|
|
try:
|
|
sg = client.security_group_create(name=self.name)
|
|
except Exception as ex:
|
|
raise exc.EResourceCreation(type='kubernetes',
|
|
message=str(ex))
|
|
data = obj.data
|
|
data[self.SECURITY_GROUP] = sg.id
|
|
cluster_obj.Cluster.update(ctx, obj.id, {'data': data})
|
|
self._set_security_group_rules(obj, sg.id)
|
|
|
|
return sg.id
|
|
|
|
def _get_security_group(self, obj):
|
|
ctx = context.get_service_context(user_id=obj.user,
|
|
project_id=obj.project)
|
|
if obj.cluster_id:
|
|
cluster = cluster_obj.Cluster.get(ctx, obj.cluster_id)
|
|
return cluster.data.get(self.SECURITY_GROUP)
|
|
return None
|
|
|
|
def _set_security_group_rules(self, obj, sgid):
|
|
client = self.network(obj)
|
|
open_ports = {
|
|
'tcp': [22, 80, 8000, 8080, 6443, 8001, 8443, 443,
|
|
179, 8082, 8086],
|
|
'udp': [8285, 8472],
|
|
'icmp': [None]
|
|
}
|
|
for p in open_ports.keys():
|
|
for port in open_ports[p]:
|
|
try:
|
|
client.security_group_rule_create(sgid, port, protocol=p)
|
|
except Exception as ex:
|
|
raise exc.EResourceCreation(type='kubernetes',
|
|
message=str(ex))
|
|
|
|
def _delete_security_group(self, obj):
|
|
sgid = obj.data.get(self.SECURITY_GROUP)
|
|
if sgid:
|
|
try:
|
|
self.network(obj).security_group_delete(sgid,
|
|
ignore_missing=True)
|
|
except exc.InternalError as ex:
|
|
raise exc.EResourceDeletion(type='kubernetes',
|
|
id=sgid,
|
|
message=str(ex))
|
|
|
|
def do_validate(self, obj):
|
|
"""Validate if the spec has provided valid info for server creation.
|
|
|
|
:param obj: The node object.
|
|
"""
|
|
# validate flavor
|
|
flavor = self.properties[self.FLAVOR]
|
|
self._validate_flavor(obj, flavor)
|
|
|
|
# validate image
|
|
image = self.properties[self.IMAGE]
|
|
if image is not None:
|
|
self._validate_image(obj, image)
|
|
|
|
# validate key_name
|
|
keypair = self.properties[self.KEY_NAME]
|
|
if keypair is not None:
|
|
self._validate_keypair(obj, keypair)
|
|
|
|
return True
|