1414# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515# See the License for the specific language governing permissions and
1616# limitations under the License.
17-
17+ import json
18+ import jmespath
1819from ansible .module_utils .basic import AnsibleModule
1920from ansible_collections .cloudera .cloud .plugins .module_utils .cdp_common import CdpModule
2021
8990 cluster_subnets:
9091 description:
9192 - Subnet ids that will be assigned to the Kubernetes cluster
93+ - Mutually exclusive with the cluster_subnets_filter option
9294 type: list
9395 required: False
96+ cluster_subnets_filter:
97+ description:
98+ - JMESPath expression to filter the subnets to be used for the Kubernetes cluster
99+ - The expression will be applied to the full list of subnets for the specified environment
100+ - Each subnet in the list is an object with the following attributes: subnetId, subnetName, availabilityZone, cidr
101+ - The filter expression must only filter the list, but not apply any attribute projection
102+ - Mutually exclusive with the cluster_subnets option
103+ type: str
104+ required: False
94105 loadbalancer_subnets:
95106 description:
96107 - Subnet ids that will be assigned to the load balancer
108+ - Mutually exclusive with the loadbalancer_subnets_filter option
97109 type: list
98110 required: False
111+ loadbalancer_subnets_filter:
112+ description:
113+ - JMESPath expression to filter the subnets to be used for the load balancer
114+ - The expression will be applied to the full list of subnets for the specified environment
115+ - Each subnet in the list is an object with the following attributes: subnetId, subnetName, availabilityZone, cidr
116+ - The filter expression must only filter the list, but not apply any attribute projection
117+ - Mutually exclusive with the cluster_subnets option
118+ type: str
119+ required: False
99120 persist:
100121 description: Whether or not to retain the database records of related entities during removal.
101122 type: bool
157178 nodes_min: 3
158179 nodes_max: 10
159180 public_loadbalancer: True
181+ cluster_subnets_filter: "[?contains(subnetName, 'pvt')]"
182+ loadbalancer_subnets_filter: "[?contains(subnetName, 'pub')]"
160183 kube_ip_ranges: ['192.168.0.1/24']
161184 state: present
162185 wait: yes
@@ -275,7 +298,9 @@ def __init__(self, module):
275298 self .lb_ip_ranges = self ._get_param ('loadbalancer_ip_ranges' )
276299 self .kube_ip_ranges = self ._get_param ('kube_ip_ranges' )
277300 self .cluster_subnets = self ._get_param ('cluster_subnets' )
301+ self .cluster_subnets_filter = self ._get_param ('cluster_subnets_filter' )
278302 self .lb_subnets = self ._get_param ('loadbalancer_subnets' )
303+ self .lb_subnets_filter = self ._get_param ('loadbalancer_subnets_filter' )
279304 self .persist = self ._get_param ('persist' )
280305 self .terminate = self ._get_param ('terminate' )
281306 self .force = self ._get_param ('force' )
@@ -330,6 +355,21 @@ def process(self):
330355 self .module .fail_json (msg = "Could not retrieve CRN for CDP Environment %s" % original_env_crn )
331356 else :
332357 # create DF Service
358+ if self .cluster_subnets_filter or self .lb_subnets_filter :
359+ try :
360+ env_info = self .cdpy .environments .describe_environment (self .env_crn )
361+ subnet_metadata = list (env_info ['network' ]['subnetMetadata' ].values ())
362+ except Exception :
363+ subnet_metadata = []
364+ if not subnet_metadata :
365+ self .module .fail_json (
366+ msg = "Could not retrieve subnet metadata for CDP Environment %s" % self .env_crn )
367+
368+ if self .cluster_subnets_filter :
369+ self .cluster_subnets = self ._filter_subnets (self .cluster_subnets_filter , subnet_metadata )
370+ if self .lb_subnets_filter :
371+ self .lb_subnets = self ._filter_subnets (self .lb_subnets_filter , subnet_metadata )
372+
333373 if not self .module .check_mode :
334374 self .service = self .cdpy .df .enable_service (
335375 env_crn = self .env_crn ,
@@ -356,6 +396,27 @@ def _wait_for_enabled(self):
356396 delay = self .delay , timeout = self .timeout
357397 )
358398
399+ def _filter_subnets (self , query , subnets ):
400+ """Apply a JMESPath to an array of subnets and return the id of the selected subnets.
401+ The query must only filter the array, without applying any projection. The query result must also be an
402+ array of subnet objects.
403+
404+ :param query: JMESpath query to filter the subnet array.
405+ :param subnets: An array of subnet objects. Each subnet in the array is an object with the following attributes:
406+ subnetId, subnetName, availabilityZone, cidr.
407+ :return: An array of subnet ids.
408+ """
409+ filtered_subnets = []
410+ try :
411+ filtered_subnets = jmespath .search (query , subnets )
412+ except Exception :
413+ self .module .fail_json (msg = "The specified subnet filter is an invalid JMESPath expression: " % query )
414+ try :
415+ return [s ['subnetId' ] for s in filtered_subnets ]
416+ except Exception :
417+ self .module .fail_json (msg = 'The subnet filter "%s" should return an array of subnet objects '
418+ 'but instead returned this: %s' % (query , json .dumps (filtered_subnets )))
419+
359420 def _disable_df (self ):
360421 # Attempt clean Disable, which also ensures we have tried at least once before we do a forced removal
361422 if self .target ['status' ]['state' ] in self .cdpy .sdk .REMOVABLE_STATES :
@@ -412,7 +473,9 @@ def main():
412473 loadbalancer_ip_ranges = dict (type = 'list' , elements = 'str' , default = None ),
413474 kube_ip_ranges = dict (type = 'list' , elements = 'str' , default = None ),
414475 cluster_subnets = dict (type = 'list' , elements = 'str' , default = None ),
476+ cluster_subnets_filter = dict (type = 'str' , default = None ),
415477 loadbalancer_subnets = dict (type = 'list' , elements = 'str' , default = None ),
478+ loadbalancer_subnets_filter = dict (type = 'str' , default = None ),
416479 persist = dict (type = 'bool' , default = False ),
417480 terminate = dict (type = 'bool' , default = False ),
418481 tags = dict (required = False , type = 'dict' , default = None ),
@@ -426,7 +489,11 @@ def main():
426489 required_if = [
427490 ('state' , 'present' , ('env_crn' , ), False ),
428491 ('state' , 'absent' , ('df_crn' , ), False )
429- ]
492+ ],
493+ mutually_exclusive = [
494+ ('cluster_subnets' , 'cluster_subnets_filter' ),
495+ ('loadbalancer_subnets' , 'loadbalancer_subnets_filter' ),
496+ ],
430497 )
431498
432499 result = DFService (module )
0 commit comments