123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- # pylint: skip-file
- # flake8: noqa
- class ManageNodeException(Exception):
- ''' manage-node exception class '''
- pass
- class ManageNodeConfig(OpenShiftCLIConfig):
- ''' ManageNodeConfig is a DTO for the manage-node command.'''
- def __init__(self, kubeconfig, node_options):
- super(ManageNodeConfig, self).__init__(None, None, kubeconfig, node_options)
- # pylint: disable=too-many-instance-attributes
- class ManageNode(OpenShiftCLI):
- ''' Class to wrap the oc command line tools '''
- # pylint allows 5
- # pylint: disable=too-many-arguments
- def __init__(self,
- config,
- verbose=False):
- ''' Constructor for ManageNode '''
- super(ManageNode, self).__init__(None, config.kubeconfig)
- self.config = config
- def evacuate(self):
- ''' formulate the params and run oadm manage-node '''
- return self._evacuate(node=self.config.config_options['node']['value'],
- selector=self.config.config_options['selector']['value'],
- pod_selector=self.config.config_options['pod_selector']['value'],
- dry_run=self.config.config_options['dry_run']['value'],
- grace_period=self.config.config_options['grace_period']['value'],
- force=self.config.config_options['force']['value'],
- )
- def get_nodes(self, node=None, selector=''):
- '''perform oc get node'''
- _node = None
- _sel = None
- if node:
- _node = node
- if selector:
- _sel = selector
- results = self._get('node', rname=_node, selector=_sel)
- if results['returncode'] != 0:
- return results
- nodes = []
- items = None
- if results['results'][0]['kind'] == 'List':
- items = results['results'][0]['items']
- else:
- items = results['results']
- for node in items:
- _node = {}
- _node['name'] = node['metadata']['name']
- _node['schedulable'] = True
- if 'unschedulable' in node['spec']:
- _node['schedulable'] = False
- nodes.append(_node)
- return nodes
- def get_pods_from_node(self, node, pod_selector=None):
- '''return pods for a node'''
- results = self._list_pods(node=[node], pod_selector=pod_selector)
- if results['returncode'] != 0:
- return results
- # When a selector or node is matched it is returned along with the json.
- # We are going to split the results based on the regexp and then
- # load the json for each matching node.
- # Before we return we are going to loop over the results and pull out the node names.
- # {'node': [pod, pod], 'node': [pod, pod]}
- # 3.2 includes the following lines in stdout: "Listing matched pods on node:"
- all_pods = []
- if "Listing matched" in results['results']:
- listing_match = re.compile('\n^Listing matched.*$\n', flags=re.MULTILINE)
- pods = listing_match.split(results['results'])
- for pod in pods:
- if pod:
- all_pods.extend(json.loads(pod)['items'])
- # 3.3 specific
- else:
- # this is gross but I filed a bug...
- # https://bugzilla.redhat.com/show_bug.cgi?id=1381621
- # build our own json from the output.
- all_pods = json.loads(results['results'])['items']
- return all_pods
- def list_pods(self):
- ''' run oadm manage-node --list-pods'''
- _nodes = self.config.config_options['node']['value']
- _selector = self.config.config_options['selector']['value']
- _pod_selector = self.config.config_options['pod_selector']['value']
- if not _nodes:
- _nodes = self.get_nodes(selector=_selector)
- else:
- _nodes = [{'name': name} for name in _nodes]
- all_pods = {}
- for node in _nodes:
- results = self.get_pods_from_node(node['name'], pod_selector=_pod_selector)
- if isinstance(results, dict):
- return results
- all_pods[node['name']] = results
- results = {}
- results['nodes'] = all_pods
- results['returncode'] = 0
- return results
- def schedulable(self):
- '''oadm manage-node call for making nodes unschedulable'''
- nodes = self.config.config_options['node']['value']
- selector = self.config.config_options['selector']['value']
- if not nodes:
- nodes = self.get_nodes(selector=selector)
- else:
- tmp_nodes = []
- for name in nodes:
- tmp_result = self.get_nodes(name)
- if isinstance(tmp_result, dict):
- tmp_nodes.append(tmp_result)
- continue
- tmp_nodes.extend(tmp_result)
- nodes = tmp_nodes
- # This is a short circuit based on the way we fetch nodes.
- # If node is a dict/list then we've already fetched them.
- for node in nodes:
- if isinstance(node, dict) and 'returncode' in node:
- return {'results': nodes, 'returncode': node['returncode']}
- if isinstance(node, list) and 'returncode' in node[0]:
- return {'results': nodes, 'returncode': node[0]['returncode']}
- # check all the nodes that were returned and verify they are:
- # node['schedulable'] == self.config.config_options['schedulable']['value']
- if any([node['schedulable'] != self.config.config_options['schedulable']['value'] for node in nodes]):
- results = self._schedulable(node=self.config.config_options['node']['value'],
- selector=self.config.config_options['selector']['value'],
- schedulable=self.config.config_options['schedulable']['value'])
- # 'NAME STATUS AGE\\nip-172-31-49-140.ec2.internal Ready 4h\\n' # E501
- # normalize formatting with previous return objects
- if results['results'].startswith('NAME'):
- nodes = []
- # removing header line and trailing new line character of node lines
- for node_results in results['results'].split('\n')[1:-1]:
- parts = node_results.split()
- nodes.append({'name': parts[0], 'schedulable': parts[1] == 'Ready'})
- results['nodes'] = nodes
- return results
- results = {}
- results['returncode'] = 0
- results['changed'] = False
- results['nodes'] = nodes
- return results
- @staticmethod
- def run_ansible(params, check_mode):
- '''run the idempotent ansible code'''
- nconfig = ManageNodeConfig(params['kubeconfig'],
- {'node': {'value': params['node'], 'include': True},
- 'selector': {'value': params['selector'], 'include': True},
- 'pod_selector': {'value': params['pod_selector'], 'include': True},
- 'schedulable': {'value': params['schedulable'], 'include': True},
- 'list_pods': {'value': params['list_pods'], 'include': True},
- 'evacuate': {'value': params['evacuate'], 'include': True},
- 'dry_run': {'value': params['dry_run'], 'include': True},
- 'force': {'value': params['force'], 'include': True},
- 'grace_period': {'value': params['grace_period'], 'include': True},
- })
- oadm_mn = ManageNode(nconfig)
- # Run the oadm manage-node commands
- results = None
- changed = False
- if params['schedulable'] != None:
- if check_mode:
- # schedulable returns results after the fact.
- # We need to redo how this works to support check_mode completely.
- return {'changed': True, 'msg': 'CHECK_MODE: would have called schedulable.'}
- results = oadm_mn.schedulable()
- if 'changed' not in results:
- changed = True
- if params['evacuate']:
- results = oadm_mn.evacuate()
- changed = True
- elif params['list_pods']:
- results = oadm_mn.list_pods()
- if not results or results['returncode'] != 0:
- return {'failed': True, 'msg': results}
- return {'changed': changed, 'results': results, 'state': "present"}
|