Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions common/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ parameters:
object_id_info:
delimiter: ":"
ids_delimiter: ";"
node_id_info:
delimiter: ";"
fcs_delimiter: ":"

connectivity_type:
nvme_over_fc: "nvmeofc"
Expand Down
13 changes: 3 additions & 10 deletions controllers/common/node_info.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
from dataclasses import dataclass, field

import controllers.servers.settings as servers_settings
from controllers.array_action import settings as array_config
from controllers.common import utils


class NodeIdInfo:
def __init__(self, node_id):
"""
Args:
node_id: <node_name>,<iqn>,<wwns>
"""
node_name, nvme_nqn, fc_wwns_str, iscsi_iqn = utils.get_node_id_info(node_id)
fc_wwns = fc_wwns_str.split(servers_settings.PARAMETERS_FC_WWN_DELIMITER)
self.node_name = node_name
self.initiators = Initiators([nvme_nqn], fc_wwns, [iscsi_iqn])
self.node_name = node_id


@dataclass
class Initiators:
"""
Object containing node initiators (e.g. iqn, fc_wwns)
Usage:
inits = Initiators([nvme_nqn], fc_wwns, [iscsi_iqn])
"""
nvme_nqns: list = field(default_factory=list)
fc_wwns: list = field(default_factory=list)
Expand Down
6 changes: 3 additions & 3 deletions controllers/common/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from controllers.common.config import config

NAME_PREFIX_SEPARATOR = "_"
ENDPOINTS_SEPARATOR = ", "

Expand All @@ -11,7 +9,6 @@
ARRAY_TYPE_DS8K = 'DS8K'
ALL_ARRAY_TYPES = [ARRAY_TYPE_XIV, ARRAY_TYPE_SVC, ARRAY_TYPE_DS8K]

PARAMETERS_NODE_ID_DELIMITER = config.parameters.node_id_info.delimiter
SPACE_EFFICIENCY_THIN = "thin"
SPACE_EFFICIENCY_COMPRESSED = "compressed"
SPACE_EFFICIENCY_DEDUPLICATED = "deduplicated"
Expand All @@ -26,9 +23,12 @@
HOST_DEFINITION_NODE_ID_FIELD = 'nodeId'
NAME_FIELD = 'name'
NAMESPACE_FIELD = 'namespace'
ANNOTATIONS_FIELD = 'annotations'
IO_GROUP_DELIMITER = ':'
IO_GROUP_LABEL_PREFIX = 'hostdefiner.block.csi.ibm.com/io-group-'

NODE_INITIATORS_FIELD = 'block.csi.ibm.com/node-initiators'

EAR_VOLUME_FC_MAP_COUNT = "2"

SCSI_PROTOCOL = 'scsi'
Expand Down
19 changes: 0 additions & 19 deletions controllers/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

import urllib3

from controllers.common import settings
from controllers.common.csi_logger import get_stdout_logger
from controllers.servers import messages

logger = get_stdout_logger()

Expand Down Expand Up @@ -44,23 +42,6 @@ def string_to_array(str_val, separator):
return res


def get_node_id_info(node_id):
logger.debug("getting node info for node id : {0}".format(node_id))
split_node = node_id.split(settings.PARAMETERS_NODE_ID_DELIMITER)
hostname, nvme_nqn, fc_wwns, iscsi_iqn = "", "", "", ""
if len(split_node) == 4:
hostname, nvme_nqn, fc_wwns, iscsi_iqn = split_node
elif len(split_node) == 3:
hostname, nvme_nqn, fc_wwns = split_node
elif len(split_node) == 2:
hostname, nvme_nqn = split_node
else:
raise ValueError(messages.WRONG_FORMAT_MESSAGE.format("node id"))
logger.debug("node name : {0}, nvme_nqn: {1}, fc_wwns : {2}, iscsi_iqn : {3} ".format(
hostname, nvme_nqn, fc_wwns, iscsi_iqn))
return hostname, nvme_nqn, fc_wwns, iscsi_iqn


def _get_config_map_info():
result = {}

Expand Down
4 changes: 2 additions & 2 deletions controllers/servers/csi/csi_controller_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def ControllerPublishVolume(self, request, context):
volume_id = volume_id_info.ids.uid
node_id_info = NodeIdInfo(request.node_id)
node_name = node_id_info.node_name
initiators = node_id_info.initiators
initiators = utils.get_node_initiators(node_name)

logger.debug("node name for this publish operation is : {0}".format(node_name))

Expand Down Expand Up @@ -273,7 +273,7 @@ def ControllerUnpublishVolume(self, request, context):
volume_id = volume_id_info.ids.uid
node_id_info = NodeIdInfo(request.node_id)
node_name = node_id_info.node_name
initiators = node_id_info.initiators
initiators = utils.get_node_initiators(node_name)
logger.debug("node name for this unpublish operation is : {0}".format(node_name))

array_connection_info = utils.get_array_connection_info_from_secrets(request.secrets,
Expand Down
1 change: 1 addition & 0 deletions controllers/servers/csi/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ munch==4.0.0
retry2==0.9.5
packaging==25.0
base58==2.1.1
kubernetes==33.1.0

# A9000 python client
pyxcli==1.2.1
Expand Down
14 changes: 13 additions & 1 deletion controllers/servers/host_definer/hd_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ class DefineHostRequest:
prefix: str = ''
connectivity_type_from_user: str = ''
node_id_from_host_definition: str = ''
node_initiators_from_host_definition: str = ''
node_id_from_csi_node: str = ''
node_initiators_from_csi_node: str = ''
array_connection_info: ArrayConnectionInfo = ArrayConnectionInfo(array_addresses='', user='', password='',
partition_name='', partition_vg='', port_set='')
io_group: str = ''
Expand All @@ -18,7 +20,8 @@ class DefineHostRequest:
class DefineHostResponse:
error_message: str = ''
connectivity_type: str = ''
ports: list = field(default_factory=list)
ports: list = field(default_factory=list) # The ports
# that actually found in storage (see _generate_response in host_definer_server.py)
node_name_on_storage: str = ''
io_group: list = field(default_factory=list)
management_address: str = ''
Expand All @@ -40,6 +43,7 @@ class HostDefinitionInfo:
secret_namespace: str = ''
node_name: str = ''
node_id: str = ''
node_initiators: str = ''
phase: str = ''
resource_version: str = ''
uid: str = ''
Expand All @@ -50,8 +54,15 @@ class HostDefinitionInfo:

@dataclass
class CsiNodeInfo:
"""
class to store CsiNodeInfo.
Typically - name and node_id can be extracted from csinode manifest
node_initiators should be extracted from the node annotations.
(See function: _generate_csi_node_info)
"""
name: str = ''
node_id: str = ''
node_initiators: str = ''


@dataclass
Expand All @@ -77,4 +88,5 @@ class ManagedNode:
def __init__(self, csi_node_info, labels):
self.name = csi_node_info.name
self.node_id = csi_node_info.node_id
self.node_initiators = csi_node_info.node_initiators
self.io_group = utils.generate_io_group_from_labels(labels)
1 change: 0 additions & 1 deletion controllers/servers/host_definer/host_definer_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def __init__(self):
self.node_watcher = NodeWatcher()

def start_host_definition(self):
logger.info('starting host definer')
self.csi_node_watcher.add_initial_csi_nodes()
self.storage_class_watcher.add_initial_storage_classes()
self.node_watcher.add_initial_nodes()
Expand Down
13 changes: 13 additions & 0 deletions controllers/servers/host_definer/kubernetes_manager/manager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"docstring"
import ast
import datetime
import base64
Expand All @@ -12,11 +13,13 @@
import controllers.common.settings as common_settings
from controllers.servers.host_definer.hd_types import (
CsiNodeInfo, PodInfo, NodeInfo, StorageClassInfo, HostDefinitionInfo)
from controllers.servers import utils as controllers_utils

logger = get_stdout_logger()


class KubernetesManager():
"""docstring"""
def __init__(self):
self._load_cluster_configuration()
self.dynamic_client = self._get_dynamic_client()
Expand Down Expand Up @@ -109,6 +112,7 @@ def _generate_csi_node_info(self, k8s_csi_node):
csi_node_info = CsiNodeInfo()
csi_node_info.name = k8s_csi_node.metadata.name
csi_node_info.node_id = self._get_node_id_from_k8s_csi_node(k8s_csi_node)
csi_node_info.node_initiators = controllers_utils.get_node_initiators_data(csi_node_info.name)
return csi_node_info

def _get_node_id_from_k8s_csi_node(self, k8s_csi_node):
Expand Down Expand Up @@ -148,8 +152,12 @@ def _generate_host_definition_info(self, k8s_host_definition):
k8s_host_definition, settings.NODE_NAME_FIELD)
host_definition_info.node_id = self._get_attr_from_host_definition(
k8s_host_definition, common_settings.HOST_DEFINITION_NODE_ID_FIELD)
host_definition_info.node_initiators = self._get_attr_from_host_definition_annotations(
k8s_host_definition, common_settings.NODE_INITIATORS_FIELD)
host_definition_info.connectivity_type = self._get_attr_from_host_definition(
k8s_host_definition, settings.CONNECTIVITY_TYPE_FIELD)
host_definition_info.ports = self._get_attr_from_host_definition(
k8s_host_definition, settings.PORTS_FIELD)
return host_definition_info

def _get_k8s_object_resource_version(self, k8s_object):
Expand All @@ -167,6 +175,11 @@ def _get_attr_from_host_definition(self, k8s_host_definition, attribute):
return getattr(k8s_host_definition.spec.hostDefinition, attribute)
return ''

def _get_attr_from_host_definition_annotations(self, k8s_host_definition, attribute):
if hasattr(k8s_host_definition.metadata.annotations, attribute):
return getattr(k8s_host_definition.metadata.annotations, attribute)
return ''

def _is_host_definition_matches(self, host_definition_info, node_name, secret_name, secret_namespace):
return host_definition_info.node_name == node_name and \
host_definition_info.secret_name == secret_name and \
Expand Down
6 changes: 4 additions & 2 deletions controllers/servers/host_definer/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
ADD_FINALIZER_TO_HOST_DEFINITION = 'Adding finalizer to host definition {}'
REMOVE_FINALIZER_TO_HOST_DEFINITION = 'Removing finalizer from host definition {}'
FAILED_TO_REMOVE_FINALIZER = 'Failed to remove {} finalizer from node'.format(settings.CSI_IBM_FINALIZER)
NODE_ID_WAS_CHANGED = "NodeId was changed for {} node, updating his ports in his definitions,"\
"old NodeId [{}], new NodeId [{}]"
NODE_INITIATORS_WERE_CHANGED = "Node initiators were changed for {} node, updating its ports definitions, " \
"old initiators: {}, new initiators: {}"
UPDATE_HOST_DEFINITION_FIELDS_FROM_STORAGE = 'Update host definition {} host from storage fields with {}'
CHECK_NODE_SHOULD_BE_MANAGED_BY_SECRET = 'Check if node {} should be managed by {} secret in {} namespace'
NODE_SHOULD_BE_MANAGED_ON_SECRET = 'Node {} should be managed by {} secret in {} namespace'
Expand Down Expand Up @@ -75,3 +75,5 @@
GENERATE_REQUEST_FOR_NODE = 'Generating define request for node {}'
COULD_NOT_CHANGE_HOST_PROTOCOL_USING_CHHOST = "Could not change host [{}] protocol using chhost command, "\
"changing the host protocol by deleting it and creating it again"
NODE_IS_NOT_MANAGED_NODE_TYPE = "Node {} is not a ManagedNode instance. This might lead to attribute errors."
NODE_ID_IS_NONE = "node_id is None !!!"
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
"""host_definer_server.py"""
import json

from controllers.array_action import settings as array_config
from controllers.array_action.errors import HostNotFoundError, HostAlreadyExists
from controllers.array_action.storage_agent import detect_array_type, get_agent
from controllers.common.csi_logger import get_stdout_logger
from controllers.common.node_info import NodeIdInfo
import controllers.common.settings as common_settings
from controllers.servers.host_definer.hd_types import DefineHostResponse
from controllers.servers.utils import join_object_prefix_with_name, get_initiators_connectivity_type
import controllers.servers.host_definer.settings as host_definer_settings
from controllers.servers.utils import (join_object_prefix_with_name,
get_initiators_connectivity_type,
generate_node_initiators_from_string_data)
from controllers.servers.host_definer import messages

logger = get_stdout_logger()
Expand All @@ -17,17 +21,17 @@ def define_host(self, request):
array_connection_info = request.array_connection_info
array_addresses = array_connection_info.array_addresses
node_id_info = NodeIdInfo(request.node_id_from_csi_node)
initiators = node_id_info.initiators
node_name = node_id_info.node_name
initiators = generate_node_initiators_from_string_data(request.node_initiators_from_csi_node)
connectivity_type_from_user = get_initiators_connectivity_type(initiators, request.connectivity_type_from_user)
host_name = join_object_prefix_with_name(prefix=request.prefix, name=node_name)
logger.info(messages.DEFINE_NODE_ON_ARRAYS.format(node_name, array_addresses))
try:
array_type = detect_array_type(array_addresses)
with get_agent(array_connection_info, array_type).get_mediator() as array_mediator:
try:
initiators_from_host_definition = self._get_initiators_from_node_id(
request.node_id_from_host_definition)
initiators_from_host_definition = \
generate_node_initiators_from_string_data(request.node_initiators_from_host_definition)
found_host_name = self._get_host_name(initiators_from_host_definition, array_mediator)
# Partition update is first one - verifies partition can be fixed (may fail if mapped)
self._update_host_partition(request, found_host_name,
Expand Down Expand Up @@ -56,9 +60,9 @@ def define_host(self, request):

def undefine_host(self, request):
node_id_info = NodeIdInfo(request.node_id_from_csi_node)
initiators = generate_node_initiators_from_string_data(request.node_initiators_from_csi_node)
array_connection_info = request.array_connection_info
array_addresses = array_connection_info.array_addresses
initiators = node_id_info.initiators
node_name = node_id_info.node_name
logger.info(messages.UNDEFINE_NODE_FROM_ARRAYS.format(node_name, array_addresses))
try:
Expand Down Expand Up @@ -88,7 +92,7 @@ def _update_host_partition(self, request, host_name, partition_name, array_media
raise array_errors.HostNotFoundError(host_name)

def _update_host_ports(self, request, host, array_mediator, partition_name):
initiators = self._get_initiators_from_node_id(request.node_id_from_csi_node)
initiators = generate_node_initiators_from_string_data(request.node_initiators_from_csi_node)
connectivity_type_from_user = get_initiators_connectivity_type(initiators, request.connectivity_type_from_user)
connectivity_type_from_host = array_mediator.get_host_connectivity_type(host)
if self._is_protocol_switched(connectivity_type_from_user, connectivity_type_from_host):
Expand All @@ -108,10 +112,6 @@ def _update_host_ports(self, request, host, array_mediator, partition_name):
return
raise ex

def _get_initiators_from_node_id(self, node_id):
node_id_info = NodeIdInfo(node_id)
return node_id_info.initiators

def _is_protocol_switched(self, connectivity_type_from_user, connectivity_type_from_host):
return self._is_switching_from_nvme_to_scsi(connectivity_type_from_user, connectivity_type_from_host) or \
self._is_switching_from_scsi_to_nvme(connectivity_type_from_user, connectivity_type_from_host)
Expand All @@ -136,7 +136,7 @@ def _change_host_protocol(self, array_mediator, host_name, connectivity_type_fro

def _change_host_protocol_with_chhost(self, array_mediator, host_name, connectivity_type_from_host, request):
self._remove_host_ports(array_mediator, host_name, connectivity_type_from_host)
initiators = self._get_initiators_from_node_id(request.node_id_from_csi_node)
initiators = generate_node_initiators_from_string_data(request.node_initiators_from_csi_node)
connectivity_type_from_user = get_initiators_connectivity_type(initiators, request.connectivity_type_from_user)
protocol = self._get_host_protocol(connectivity_type_from_user)
array_mediator.change_host_protocol(host_name, protocol)
Expand All @@ -161,7 +161,7 @@ def _is_protocol_nvme(self, connectivity_type):
return connectivity_type == array_config.NVME_OVER_FC_CONNECTIVITY_TYPE

def _create_host(self, host, array_mediator, request):
initiators = self._get_initiators_from_node_id(request.node_id_from_csi_node)
initiators = generate_node_initiators_from_string_data(request.node_initiators_from_csi_node)
connectivity_type = get_initiators_connectivity_type(initiators, request.connectivity_type_from_user)
array_mediator.create_host(host, initiators, connectivity_type, request.io_group,
request.array_connection_info.partition_name,
Expand All @@ -173,7 +173,8 @@ def _create_host(self, host, array_mediator, request):
def _is_port_update_needed_when_same_protocol(
self, request, connectivity_type_from_user, connectivity_type_from_host):
return connectivity_type_from_user != connectivity_type_from_host \
or request.node_id_from_csi_node != request.node_id_from_host_definition
or request.node_id_from_csi_node != request.node_id_from_host_definition \
or request.node_initiators_from_csi_node != request.node_initiators_from_host_definition

def _update_host_io_group(self, request, host, array_mediator):
io_group_from_host = array_mediator.get_host_io_group(host)
Expand Down
15 changes: 9 additions & 6 deletions controllers/servers/host_definer/watcher/csi_node_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,18 @@ def _create_definitions_when_csi_node_changed(self, csi_node_info):
host_definition_info = self._get_matching_host_definition_info(
csi_node_info.name, secret_name, secret_namespace)
if host_definition_info:
if self._is_node_id_changed(host_definition_info.node_id, csi_node_info.node_id):
logger.info(messages.NODE_ID_WAS_CHANGED.format(csi_node_info.name,
host_definition_info.node_id, csi_node_info.node_id))
if self._is_node_initiators_changed(host_definition_info, csi_node_info):
logger.info(messages.NODE_INITIATORS_WERE_CHANGED.format(csi_node_info.name,
host_definition_info.node_initiators, csi_node_info.node_initiators))
NODES[csi_node_info.name] = self._generate_managed_node(csi_node_info)
self._create_definition(host_definition_info)

def _is_node_id_changed(self, host_definition_node_id, csi_node_node_id):
return host_definition_node_id != csi_node_node_id \
and host_definition_node_id and csi_node_node_id
def _is_node_initiators_changed(self, host_definition_info, csi_node_info):
if not host_definition_info.node_id or not csi_node_info.node_id:
logger.warning(messages.NODE_ID_IS_NONE)
return False

return host_definition_info.node_initiators != csi_node_info.node_initiators

def _undefine_hosts(self, node_name):
for secret_info in MANAGED_SECRETS:
Expand Down
Loading