mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2025-10-26 13:56:09 -07:00 
			
		
		
		
	* k8s: add k8s_kind arg to KubernetesRawModule Single–kind k8s modules (e.g. k8s_service) do not have a module parameter called 'kind' and need to pass a static 'kind' on KubernetesRawModule class creation. Hence this change. * k8s: make 'validate' and 'wait' mod params optional Not all k8s modules utilizing KubernetesRawModule will use these. * k8s_service: new k8s module for handling Services
		
			
				
	
	
		
			267 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # Copyright (c) 2018, KubeVirt Team <@kubevirt>
 | |
| # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 | |
| 
 | |
| from __future__ import absolute_import, division, print_function
 | |
| 
 | |
| __metaclass__ = type
 | |
| 
 | |
| 
 | |
| ANSIBLE_METADATA = {'metadata_version': '1.1',
 | |
|                     'status': ['preview'],
 | |
|                     'supported_by': 'community'}
 | |
| 
 | |
| DOCUMENTATION = '''
 | |
| 
 | |
| module: k8s_service
 | |
| 
 | |
| short_description: Manage Services on Kubernetes
 | |
| 
 | |
| version_added: "2.8"
 | |
| 
 | |
| author: KubeVirt Team (@kubevirt)
 | |
| 
 | |
| description:
 | |
|   - Use Openshift Python SDK to manage Services on Kubernetes
 | |
| 
 | |
| extends_documentation_fragment:
 | |
|   - k8s_auth_options
 | |
| 
 | |
| options:
 | |
|   resource_definition:
 | |
|     description:
 | |
|     - A partial YAML definition of the Service object being created/updated. Here you can define Kubernetes
 | |
|       Service Resource parameters not covered by this module's parameters.
 | |
|     - "NOTE: I(resource_definition) has lower priority than module parameters. If you try to define e.g.
 | |
|       I(metadata.namespace) here, that value will be ignored and I(metadata) used instead."
 | |
|     aliases:
 | |
|     - definition
 | |
|     - inline
 | |
|     type: dict
 | |
|   state:
 | |
|     description:
 | |
|     - Determines if an object should be created, patched, or deleted. When set to C(present), an object will be
 | |
|       created, if it does not already exist. If set to C(absent), an existing object will be deleted. If set to
 | |
|       C(present), an existing object will be patched, if its attributes differ from those specified using
 | |
|       module options and I(resource_definition).
 | |
|     default: present
 | |
|     choices:
 | |
|     - present
 | |
|     - absent
 | |
|   force:
 | |
|     description:
 | |
|     - If set to C(True), and I(state) is C(present), an existing object will be replaced.
 | |
|     default: false
 | |
|     type: bool
 | |
|   merge_type:
 | |
|     description:
 | |
|     - Whether to override the default patch merge approach with a specific type. By default, the strategic
 | |
|       merge will typically be used.
 | |
|     - For example, Custom Resource Definitions typically aren't updatable by the usual strategic merge. You may
 | |
|       want to use C(merge) if you see "strategic merge patch format is not supported"
 | |
|     - See U(https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment)
 | |
|     - Requires openshift >= 0.6.2
 | |
|     - If more than one merge_type is given, the merge_types will be tried in order
 | |
|     - If openshift >= 0.6.2, this defaults to C(['strategic-merge', 'merge']), which is ideal for using the same parameters
 | |
|       on resource kinds that combine Custom Resources and built-in resources. For openshift < 0.6.2, the default
 | |
|       is simply C(strategic-merge).
 | |
|     choices:
 | |
|     - json
 | |
|     - merge
 | |
|     - strategic-merge
 | |
|     type: list
 | |
|   name:
 | |
|     description:
 | |
|       - Use to specify a Service object name.
 | |
|     required: true
 | |
|     type: str
 | |
|   namespace:
 | |
|     description:
 | |
|       - Use to specify a Service object namespace.
 | |
|     required: true
 | |
|     type: str
 | |
|   type:
 | |
|     description:
 | |
|       - Specifies the type of Service to create.
 | |
|       - See U(https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types)
 | |
|     choices:
 | |
|       - NodePort
 | |
|       - ClusterIP
 | |
|       - LoadBalancer
 | |
|       - ExternalName
 | |
|   ports:
 | |
|     description:
 | |
|       - A list of ports to expose.
 | |
|       - U(https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services)
 | |
|     type: list
 | |
|   selector:
 | |
|     description:
 | |
|       - Label selectors identify objects this Service should apply to.
 | |
|       - U(https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
 | |
|     type: dict
 | |
| 
 | |
| requirements:
 | |
|   - python >= 2.7
 | |
|   - openshift >= 0.6.2
 | |
| '''
 | |
| 
 | |
| EXAMPLES = '''
 | |
| - name: Expose https port with ClusterIP
 | |
|   k8s_service:
 | |
|     state: present
 | |
|     name: test-https
 | |
|     namespace: default
 | |
|     ports:
 | |
|     - port: 443
 | |
|       protocol: TCP
 | |
|     selector:
 | |
|       key: special
 | |
| 
 | |
| - name: Expose https port with ClusterIP using spec
 | |
|   k8s_service:
 | |
|     state: present
 | |
|     name: test-https
 | |
|     namespace: default
 | |
|     inline:
 | |
|       spec:
 | |
|         ports:
 | |
|         - port: 443
 | |
|           protocol: TCP
 | |
|         selector:
 | |
|           key: special
 | |
| '''
 | |
| 
 | |
| RETURN = '''
 | |
| result:
 | |
|   description:
 | |
|   - The created, patched, or otherwise present Service object. Will be empty in the case of a deletion.
 | |
|   returned: success
 | |
|   type: complex
 | |
|   contains:
 | |
|      api_version:
 | |
|        description: The versioned schema of this representation of an object.
 | |
|        returned: success
 | |
|        type: str
 | |
|      kind:
 | |
|        description: Always 'Service'.
 | |
|        returned: success
 | |
|        type: str
 | |
|      metadata:
 | |
|        description: Standard object metadata. Includes name, namespace, annotations, labels, etc.
 | |
|        returned: success
 | |
|        type: complex
 | |
|      spec:
 | |
|        description: Specific attributes of the object. Will vary based on the I(api_version) and I(kind).
 | |
|        returned: success
 | |
|        type: complex
 | |
|      status:
 | |
|        description: Current status details for the object.
 | |
|        returned: success
 | |
|        type: complex
 | |
| '''
 | |
| 
 | |
| import copy
 | |
| import traceback
 | |
| 
 | |
| from collections import defaultdict
 | |
| 
 | |
| from ansible.module_utils.k8s.common import AUTH_ARG_SPEC, COMMON_ARG_SPEC
 | |
| from ansible.module_utils.k8s.raw import KubernetesRawModule
 | |
| 
 | |
| 
 | |
| SERVICE_ARG_SPEC = {
 | |
|     'state': {
 | |
|         'default': 'present',
 | |
|         'choices': ['present', 'absent'],
 | |
|     },
 | |
|     'force': {
 | |
|         'type': 'bool',
 | |
|         'default': False,
 | |
|     },
 | |
|     'resource_definition': {
 | |
|         'type': 'dict',
 | |
|         'aliases': ['definition', 'inline']
 | |
|     },
 | |
|     'name': {'required': True},
 | |
|     'namespace': {'required': True},
 | |
|     'merge_type': {'type': 'list', 'choices': ['json', 'merge', 'strategic-merge']},
 | |
|     'selector': {'type': 'dict'},
 | |
|     'type': {
 | |
|         'type': 'str',
 | |
|         'choices': [
 | |
|             'NodePort', 'ClusterIP', 'LoadBalancer', 'ExternalName'
 | |
|         ],
 | |
|     },
 | |
|     'ports': {'type': 'list'},
 | |
| }
 | |
| 
 | |
| 
 | |
| class KubernetesService(KubernetesRawModule):
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super(KubernetesService, self).__init__(*args, k8s_kind='Service', **kwargs)
 | |
| 
 | |
|     @staticmethod
 | |
|     def merge_dicts(x, y):
 | |
|         for k in set(x.keys()).union(y.keys()):
 | |
|             if k in x and k in y:
 | |
|                 if isinstance(x[k], dict) and isinstance(y[k], dict):
 | |
|                     yield (k, dict(KubernetesService.merge_dicts(x[k], y[k])))
 | |
|                 else:
 | |
|                     yield (k, y[k])
 | |
|             elif k in x:
 | |
|                 yield (k, x[k])
 | |
|             else:
 | |
|                 yield (k, y[k])
 | |
| 
 | |
|     @property
 | |
|     def argspec(self):
 | |
|         """ argspec property builder """
 | |
|         argument_spec = copy.deepcopy(AUTH_ARG_SPEC)
 | |
|         argument_spec.update(SERVICE_ARG_SPEC)
 | |
|         return argument_spec
 | |
| 
 | |
|     def execute_module(self):
 | |
|         """ Module execution """
 | |
|         self.client = self.get_api_client()
 | |
| 
 | |
|         api_version = 'v1'
 | |
|         selector = self.params.get('selector')
 | |
|         service_type = self.params.get('type')
 | |
|         ports = self.params.get('ports')
 | |
| 
 | |
|         definition = defaultdict(defaultdict)
 | |
| 
 | |
|         definition['kind'] = 'Service'
 | |
|         definition['apiVersion'] = api_version
 | |
| 
 | |
|         def_spec = definition['spec']
 | |
|         def_spec['type'] = service_type
 | |
|         def_spec['ports'] = ports
 | |
|         def_spec['selector'] = selector
 | |
| 
 | |
|         def_meta = definition['metadata']
 | |
|         def_meta['name'] = self.params.get('name')
 | |
|         def_meta['namespace'] = self.params.get('namespace')
 | |
| 
 | |
|         # 'resource_definition:' has lower priority than module parameters
 | |
|         definition = dict(self.merge_dicts(self.resource_definitions[0], definition))
 | |
| 
 | |
|         resource = self.find_resource('Service', api_version, fail=True)
 | |
|         definition = self.set_defaults(resource, definition)
 | |
|         result = self.perform_action(resource, definition)
 | |
| 
 | |
|         self.exit_json(**result)
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     module = KubernetesService()
 | |
|     try:
 | |
|         module.execute_module()
 | |
|     except Exception as e:
 | |
|         module.fail_json(msg=str(e), exception=traceback.format_exc())
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 |