Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move DFX Beta implementation to GA process #31

Merged
merged 2 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions docs/_sources/df.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Examples
# Note: These examples do not set authentication details.

# Create a Dataflow Service
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
nodes_min: 3
nodes_max: 10
Expand All @@ -191,7 +191,7 @@ Examples
wait: yes

# Remove a Dataflow Service with Async wait
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
persist: False
state: absent
Expand Down
4 changes: 2 additions & 2 deletions docsrc/df.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ Examples
# Note: These examples do not set authentication details.

# Create a Dataflow Service
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
nodes_min: 3
nodes_max: 10
Expand All @@ -191,7 +191,7 @@ Examples
wait: yes

# Remove a Dataflow Service with Async wait
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
persist: False
state: absent
Expand Down
2 changes: 1 addition & 1 deletion plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ modules employ the underlying SDK contained within the `cdpy` Python package.
| [datalake](./modules/datalake.py) | Create, manage, and destroy CDP Datalakes |
| [datalake_info](./modules/datalake_info.py) | Gather information about CDP Datalakes |
| [datalake_runtime_info](./modules/datalake_runtime_info.py) | Gather information about CDP Datalake Runtimes |
| [df](./modules/df.py) | Enable or disable CDP DataFlow services |
| [df](./modules/df_service.py) | Enable or disable CDP DataFlow services |
| [df_info](./modules/df_info.py) | Gather information about CDP DataFlow services |
| [dw_cluster](./modules/dw_cluster.py) | Create, manage, and destroy CDP Data Warehouse experiences |
| [dw_cluster_info](./modules/dw_cluster_info.py) | Gather information about CDP Data Warehouse experiences |
Expand Down
52 changes: 37 additions & 15 deletions plugins/modules/df_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,24 @@
options:
name:
description:
- If a name is provided, that DataFlow Service will be described.
- Must be CDP Environment CRN or string name of DataFlow Service
- If a name is provided, that DataFlow Service will be described
- Must be the string name of the CDP Environment
- Mutually exclusive with df_crn and env_crn
type: str
required: False
aliases:
- crn
df_crn:
description:
- If a df_crn is provided, that DataFlow Service will be described
- Mutually exclusive with name and env_crn
type: str
required: False
env_crn:
description:
- If an env_crn is provided, the DataFlow Service for that Environment will be described
- Mutually exclusive with name and df_crn
type: str
required: False

notes:
- This feature this module is for is in Technical Preview
extends_documentation_fragment:
Expand All @@ -59,9 +71,13 @@
- cloudera.cloud.df_info:
name: example-service

# Gather detailed information about a named DataFlow Service using a CRN
# Gather detailed information about a named DataFlow Service using a Dataflow CRN
- cloudera.cloud.df_info:
crn: example-service-crn
df_crn: crn:cdp:df:region:tenant-uuid4:service:service-uuid4

# Gather detailed information about a named DataFlow Service using an Environment CRN
- cloudera.cloud.df_info:
df_crn: crn:cdp:environments:region:tenant-uuid4:environment:environment-uuid4
'''

RETURN = r'''
Expand Down Expand Up @@ -159,32 +175,38 @@ def __init__(self, module):

# Set variables
self.name = self._get_param('name')
self.df_crn = self._get_param('df_crn')
self.env_crn = self._get_param('env_crn')

# Initialize return values
self.services = []

# Initialize internal values
self.all_services = []

# Execute logic process
self.process()

@CdpModule._Decorators.process_debug
def process(self):
if self.name: # Note that both None and '' will trigger this
if self.name.startswith('crn:'):
service_single = self.cdpy.df.describe_environment(env_crn=self.name)
if service_single is not None:
self.services.append(service_single)
else:
self.services = self.cdpy.df.list_environments(name=self.name)
# Note that parameters are defaulted to None, and are skipped if None at submission
self.all_services = self.cdpy.df.list_services(df_crn=self.df_crn, name=self.name, env_crn=self.env_crn)
if any(x is not None for x in [self.name, self.df_crn, self.env_crn]):
# Any set parameter indicates a describe is preferred to the lower information list command
self.services = [self.cdpy.df.describe_service(df_crn=x['crn']) for x in self.all_services]
else:
self.services = self.cdpy.df.list_environments()
self.services = self.all_services


def main():
module = AnsibleModule(
argument_spec=CdpModule.argument_spec(
name=dict(required=False, type='str', aliases=['crn']),
name=dict(required=False, type='str'),
Chaffelson marked this conversation as resolved.
Show resolved Hide resolved
df_crn=dict(required=False, type='str'),
env_crn=dict(required=False, type='str'),
),
supports_check_mode=True,
mutually_exclusive=['name', 'df_crn', 'env_crn']
)

result = DFInfo(module)
Expand Down
68 changes: 44 additions & 24 deletions plugins/modules/df.py → plugins/modules/df_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
# Note: These examples do not set authentication details.

# Create a Dataflow Service
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
nodes_min: 3
nodes_max: 10
Expand All @@ -129,7 +129,7 @@
wait: yes

# Remove a Dataflow Service with Async wait
- cloudera.cloud.df:
- cloudera.cloud.df_service:
name: my-service
persist: False
state: absent
Expand Down Expand Up @@ -234,12 +234,17 @@ def __init__(self, module):
super(DFService, self).__init__(module)

# Set variables
self.name = self._get_param('name')
self.env_crn = self._get_param('env_crn')
self.df_crn = self._get_param('df_crn')
self.nodes_min = self._get_param('nodes_min')
self.nodes_max = self._get_param('nodes_max')
self.public_loadbalancer = self._get_param('public_loadbalancer')
self.ip_ranges = self._get_param('ip_ranges')
self.lb_ip_ranges = self._get_param('loadbalancer_ip_ranges')
self.kube_ip_ranges = self._get_param('kube_ip_ranges')
self.cluster_subnets = self._get_param('cluster_subnets')
self.lb_subnets = self._get_param('lb_subnets')
self.persist = self._get_param('persist')
self.terminate = self._get_param('terminate')
self.force = self._get_param('force')

self.state = self._get_param('state')
Expand All @@ -252,16 +257,16 @@ def __init__(self, module):

# Initialize internal values
self.target = None
self.env_crn = None

# Execute logic process
self.process()

@CdpModule._Decorators.process_debug
def process(self):
self.env_crn = self.cdpy.environments.resolve_environment_crn(self.name)
if self.env_crn is not None:
self.target = self.cdpy.df.describe_environment(env_crn=self.name)
self.env_crn = self.cdpy.environments.resolve_environment_crn(self.env_crn)
if self.env_crn is not None or self.df_crn is not None:
self.target = self.cdpy.df.describe_service(env_crn=self.env_crn, df_crn=self.df_crn)

if self.target is not None:
# DF Database Entry exists
Expand All @@ -283,19 +288,22 @@ def process(self):
# Environment does not have DF database entry, and probably doesn't exist
if self.state in ['absent']:
self.module.log(
"Dataflow Service %s already disabled in CDP Environment %s" % (self.name, self.env_crn))
"Dataflow Service already disabled in CDP Environment %s" % self.env_crn)
elif self.state in ['present']:
if self.env_crn is None:
self.module.fail_json(msg="Could not retrieve CRN for CDP Environment %s" % self.env)
else:
# create DF Service
if not self.module.check_mode:
self.service = self.cdpy.df.enable_environment(
self.service = self.cdpy.df.enable_service(
env_crn=self.env_crn,
authorized_ips=self.ip_ranges,
min_nodes=self.nodes_min,
max_nodes=self.nodes_max,
enable_public_ip=self.public_loadbalancer
enable_public_ip=self.public_loadbalancer,
lb_ips=self.lb_ip_ranges,
kube_ips=self.kube_ip_ranges,
cluster_subnets=self.cluster_subnets,
lb_subnets=self.lb_subnets
)
if self.wait:
self.service = self._wait_for_enabled()
Expand All @@ -305,57 +313,65 @@ def process(self):

def _wait_for_enabled(self):
return self.cdpy.sdk.wait_for_state(
describe_func=self.cdpy.df.describe_environment, params=dict(env_crn=self.env_crn),
describe_func=self.cdpy.df.describe_service, params=dict(env_crn=self.env_crn),
field=['status', 'state'], state=self.cdpy.sdk.STARTED_STATES,
delay=self.delay, timeout=self.timeout
)

def _disable_df(self):
# Attempt clean Disable, which also ensures we have tried at least once before we do a forced removal
if self.target['status']['state'] in self.cdpy.sdk.REMOVABLE_STATES:
self.service = self.cdpy.df.disable_environment(
env_crn=self.env_crn,
persist=self.persist
self.service = self.cdpy.df.disable_service(
df_crn=self.df_crn,
persist=self.persist,
terminate=self.terminate
)
else:
self.module.warn("Attempting to disable DataFlow Service but state %s not in Removable States %s"
% (self.target['status']['state'], self.cdpy.sdk.REMOVABLE_STATES))
if self.wait:
# Wait for Clean Disable, if possible
self.service = self.cdpy.sdk.wait_for_state(
describe_func=self.cdpy.df.describe_environment, params=dict(env_crn=self.env_crn),
describe_func=self.cdpy.df.describe_service, params=dict(df_crn=self.df_crn),
field=['status', 'state'],
state=self.cdpy.sdk.STOPPED_STATES + self.cdpy.sdk.REMOVABLE_STATES + [None],
delay=self.delay, timeout=self.timeout, ignore_failures=True
)
else:
self.service = self.cdpy.df.describe_environment(env_crn=self.name)
self.service = self.cdpy.df.describe_service(df_crn=self.df_crn)
# Check disable result against need for further forced delete action, in case it didn't work first time around
if self.service is not None:
if self.service['status']['state'] in self.cdpy.sdk.REMOVABLE_STATES:
if self.force:
self.service = self.cdpy.df.delete_environment(
env_crn=self.env_crn
self.service = self.cdpy.df.reset_service(
df_crn=self.df_crn
)
else:
self.module.fail_json(msg="DF Service Disable failed and Force delete not requested")
if self.wait:
self.service = self.cdpy.sdk.wait_for_state(
describe_func=self.cdpy.df.describe_environment, params=dict(env_crn=self.env_crn),
describe_func=self.cdpy.df.describe_service, params=dict(df_crn=self.df_crn),
field=None, # This time we require removal or declare failure
delay=self.delay, timeout=self.timeout
)
else:
self.service = self.cdpy.df.describe_environment(env_crn=self.name)
self.service = self.cdpy.df.describe_service(df_crn=self.df_crn)


def main():
module = AnsibleModule(
Chaffelson marked this conversation as resolved.
Show resolved Hide resolved
argument_spec=CdpModule.argument_spec(
name=dict(required=True, type='str', aliases=['crn', 'env_crn']),
env_crn=dict(required=False, type='str'),
Chaffelson marked this conversation as resolved.
Show resolved Hide resolved
df_crn=dict(required=False, type='str'),
nodes_min=dict(required=False, type='int', default=3, aliases=['min_k8s_node_count']),
nodes_max=dict(required=False, type='int', default=3, aliases=['max_k8s_node_count']),
public_loadbalancer=dict(required=False, type='bool', default=False, aliases=['use_public_load_balancer']),
ip_ranges=dict(required=False, type='list', elements='str', default=list(),
aliases=['authorized_ip_ranges']),
loadbalancer_ip_ranges=dict(required=False, type='list', elements='str', default=None),
kube_ip_ranges=dict(required=False, type='list', elements='str', default=None),
cluster_subnets=dict(required=False, type='list', elements='str', default=None),
loadbalancer_subnets=dict(required=False, type='list', elements='str', default=None),
persist=dict(required=False, type='bool', default=False),
terminate=dict(required=False, type='bool', default=False),
state=dict(required=False, type='str', choices=['present', 'absent'],
default='present'),
force=dict(required=False, type='bool', default=False, aliases=['force_delete']),
Expand All @@ -364,6 +380,10 @@ def main():
timeout=dict(required=False, type='int', aliases=['polling_timeout'], default=3600)
),
supports_check_mode=True,
required_if=[
('state', 'present', ('env_crn', ), False),
('state', 'absent', ('df_crn', ), False)
]
)

result = DFService(module)
Expand Down
2 changes: 1 addition & 1 deletion plugins/modules/env_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def process(self):
for this_env in self.environments:
df = None
# Removing until DF is GA so we are not dependent on Beta functionality
# df = self.cdpy.df.describe_environment(this_env['crn'])
df = self.cdpy.df.list_services(env_crn=this_env['crn'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is scope creep! #21

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently safe delete of an environment relies on this functionality, agree that it should be cleaned up to not need it but I don't want to cross the streams.

this_env['descendants'] = {
'datahub': self.cdpy.datahub.describe_all_clusters(this_env['environmentName']),
'dw': self.cdpy.dw.gather_clusters(this_env['crn']),
Expand Down