Skip to content

Commit

Permalink
[DEVOPS-640] Add wait for mutation action
Browse files Browse the repository at this point in the history
  • Loading branch information
yusufhm committed Oct 12, 2024
1 parent c04f7f5 commit 13eb9a2
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 13 deletions.
49 changes: 48 additions & 1 deletion api/plugins/action/mutation.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
from . import LagoonActionBase
from gql.dsl import DSLMutation
from gql.dsl import DSLMutation, DSLQuery
from time import sleep
from typing import Any, Dict

class ActionModule(LagoonActionBase):

WAIT_QUERIES = {
'invokeRegisteredTask': {
'query': 'taskById',
'matchField': 'id',
'statusField': 'status',
}
}

def run(self, tmp=None, task_vars=None):

if task_vars is None:
Expand All @@ -16,11 +26,48 @@ def run(self, tmp=None, task_vars=None):
mutation = self._task.args.get('mutation')
mutationArgs = self._task.args.get('arguments')
subfields = self._task.args.get('subfields', ['id'])
wait = self._task.args.get('wait', False)
waitCondition = self._task.args.get('waitCondition', {
'field': 'status',
'value': 'complete',
})

with self.client:
mutationObj = self.client.build_dynamic_mutation(
mutation, mutationArgs, subfields)
res = self.client.execute_query_dynamic(DSLMutation(mutationObj))
result['result'] = res[mutation]
result['changed'] = True

if wait and mutation in self.WAIT_QUERIES:
waitQuery = self.WAIT_QUERIES[mutation]

qryArgs = {}
if isinstance(waitQuery["matchField"], str):
qryArgs = {waitQuery["matchField"]: res[mutation][waitQuery["matchField"]]}
else:
# Use a dictionary to match differing field names.
pass

waitQry = self.client.build_dynamic_query(
query=waitQuery["query"],
args=qryArgs,
fields=[waitQuery["statusField"]],
)
waitResult = self.waitQuery(waitQuery["query"], waitQry, waitCondition)
result['wait'] = waitResult
return result

def waitQuery(self, qryName, waitQry, waitCondition) -> Dict[str, Any]:
waitResult = self.client.execute_query_dynamic(DSLQuery(waitQry))

while not self.evaluateWaitCondition(qryName, waitResult, waitCondition):
sleep(5)
waitResult = self.client.execute_query_dynamic(DSLQuery(waitQry))

return waitResult

def evaluateWaitCondition(self, qryName, waitResult, waitCondition) -> bool:
if waitCondition["field"] in waitResult[qryName]:
return waitResult[qryName][waitCondition["field"]] == waitCondition["value"]
return False
6 changes: 4 additions & 2 deletions api/plugins/action/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ def run(self, tmp=None, task_vars=None):
self.createClient(task_vars)

query = self._task.args.get('query')
mainType = self._task.args.get('mainType')
args = self._task.args.get('args', {})
fields = self._task.args.get('fields', [])
subFields = self._task.args.get('subFields', {})

with self.client:
queryObj = self.client.build_dynamic_query(
query, mainType, args, fields, subFields)
query=query,
args=args,
fields=fields,
subFieldsMap=subFields)
res = self.client.execute_query_dynamic(DSLQuery(queryObj))
result['result'] = res[query]
return result
2 changes: 2 additions & 0 deletions api/plugins/action/task_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class ActionModule(LagoonMutationActionBase):
"advancedTaskDefinitionArguments",
"deployTokenInjection",
"projectKeyInjection",
"image",
"groupName"
],
),
# Configuration for deleting a task definition.
Expand Down
4 changes: 2 additions & 2 deletions api/plugins/module_utils/gql.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def execute_query_dynamic(self, *operations: DSLExecutable) -> Dict[str, Any]:

def build_dynamic_query(self,
query: str,
mainType: str,
mainType: str = "",
args: Optional[Dict[str, Any]] = {},
fields: List[str] = [],
subFieldsMap: Optional[Dict[str, List[str]]] = {},
Expand All @@ -174,7 +174,6 @@ def build_dynamic_query(self,
}
query = "projectByName"
args = {"name": "test-project"}
mainType = "Project" (since projectByName returns Project)
fields = ["id", "name"]
subFieldsMap = {
"kubernetes": {
Expand All @@ -192,6 +191,7 @@ def build_dynamic_query(self,
if len(args):
queryObj.args(**args)

mainType: str = queryObj.field.type.name
mainTypeObj: DSLType = getattr(self.ds, mainType)

# Top-level fields.
Expand Down
36 changes: 32 additions & 4 deletions api/plugins/modules/mutation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: mutation
description: Run a mutation against the Lagoon GraphQL API.
short_description: Run a mutation against the Lagoon GraphQL API.
Expand All @@ -21,9 +21,26 @@
- The subfields to select from the mutation result.
type: list
default: [id]
'''
wait:
description:
- Whether to wait for the mutation to complete.
type: bool
default: false
waitCondition:
description:
- The condition to wait for before returning.
type: dict
default: {field: status, value: complete}
suboptions:
field:
description: The field to use as status.
type: str
value:
description: The value to wait for.
type: str
"""

EXAMPLES = r'''
EXAMPLES = r"""
- name: Delete a Fact via mutation before creating
lagoon.api.mutation:
mutation: deleteFact
Expand Down Expand Up @@ -68,4 +85,15 @@
value: 4.0.0
source: ansible_playbook:audit:module_version
description: The panelizer module version
'''
- name: Invoke Lagoon task and wait for completion
lagoon.api.mutation:
mutation: invokeRegisteredTask
arguments:
advancedTaskDefinition: -1
environment: -1
argumentValues:
- advancedTaskDefinitionArgumentName: SOME_ARG_NAME
value: SOME_ARG_VALUE
wait: true
"""
6 changes: 2 additions & 4 deletions api/plugins/modules/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
default: {}
mainType:
description:
- The GraphQL type from which to retrieve the top-level fields.
- The GraphQL type from which to retrieve the top-level fields - DEPRECATED.
- The type is now inferred from the GraphQL schema.
type: str
fields:
description:
Expand Down Expand Up @@ -46,7 +47,6 @@
- name: Query specific fields for all projects.
lagoon.api.query:
query: allProjects
mainType: Project
fields:
- id
- name
Expand All @@ -57,7 +57,6 @@
query: projectByName
args:
name: '{{ project_name }}'
mainType: Project
fields:
- id
- name
Expand All @@ -76,7 +75,6 @@
query: projectByName
args:
name: '{{ project_name }}'
mainType: Project
subFields:
envVariables:
type: EnvKeyValue
Expand Down

0 comments on commit 13eb9a2

Please sign in to comment.