Skip to content

Commit ed7673c

Browse files
authored
Add option to produce pipelinerun taskspec as taskref (#810)
* add option to produce taskspec as taskref * add rbac for task templates
1 parent c8b258c commit ed7673c

File tree

9 files changed

+118
-0
lines changed

9 files changed

+118
-0
lines changed

manifests/kustomize/base/installs/multi-user/api-service/cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ rules:
5454
- taskruns
5555
- conditions
5656
- runs
57+
- tasks
5758
verbs:
5859
- create
5960
- get

manifests/kustomize/base/installs/multi-user/pipelines-ui/cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ rules:
4646
- pipelineruns
4747
- taskruns
4848
- conditions
49+
- tasks
4950
verbs:
5051
- create
5152
- get

manifests/kustomize/base/installs/multi-user/scheduled-workflow/cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ rules:
4141
- taskruns
4242
- conditions
4343
- runs
44+
- tasks
4445
verbs:
4546
- create
4647
- get

manifests/kustomize/base/pipeline/ml-pipeline-apiserver-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ rules:
3333
- taskruns
3434
- conditions
3535
- runs
36+
- tasks
3637
verbs:
3738
- create
3839
- get

manifests/kustomize/base/pipeline/ml-pipeline-scheduledworkflow-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ rules:
4343
- taskruns
4444
- conditions
4545
- runs
46+
- tasks
4647
verbs:
4748
- create
4849
- get

manifests/kustomize/base/pipeline/ml-pipeline-ui-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ rules:
4848
- pipelineruns
4949
- taskruns
5050
- conditions
51+
- tasks
5152
verbs:
5253
- create
5354
- get

manifests/kustomize/base/pipeline/pipeline-runner-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ rules:
8585
- taskruns
8686
- conditions
8787
- runs
88+
- tasks
8889
verbs:
8990
- create
9091
- get
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Copyright 2020 kubeflow.org
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from kfp import dsl
16+
from kfp import components
17+
18+
def random_num(low:int, high:int) -> int:
19+
"""Generate a random number between low and high."""
20+
import random
21+
result = random.randint(low, high)
22+
print(result)
23+
return result
24+
25+
def flip_coin() -> str:
26+
"""Flip a coin and output heads or tails randomly."""
27+
import random
28+
result = 'heads' if random.randint(0, 1) == 0 else 'tails'
29+
print(result)
30+
return result
31+
32+
def print_msg(msg: str):
33+
"""Print a message."""
34+
print(msg)
35+
36+
37+
flip_coin_op = components.create_component_from_func(
38+
flip_coin, base_image='python:alpine3.6')
39+
print_op = components.create_component_from_func(
40+
print_msg, base_image='python:alpine3.6')
41+
random_num_op = components.create_component_from_func(
42+
random_num, base_image='python:alpine3.6')
43+
44+
@dsl.pipeline(
45+
name='conditional-execution-pipeline',
46+
description='Shows how to use dsl.Condition().'
47+
)
48+
def flipcoin_pipeline():
49+
flip = flip_coin_op()
50+
with dsl.Condition(flip.output == 'heads'):
51+
random_num_head = random_num_op(0, 9)
52+
with dsl.Condition(random_num_head.output > 5):
53+
print_op('heads and %s > 5!' % random_num_head.output)
54+
with dsl.Condition(random_num_head.output <= 5):
55+
print_op('heads and %s <= 5!' % random_num_head.output)
56+
57+
with dsl.Condition(flip.output == 'tails'):
58+
random_num_tail = random_num_op(10, 19)
59+
with dsl.Condition(random_num_tail.output > 15):
60+
print_op('tails and %s > 15!' % random_num_tail.output)
61+
with dsl.Condition(random_num_tail.output <= 15):
62+
print_op('tails and %s <= 15!' % random_num_tail.output)
63+
64+
65+
if __name__ == '__main__':
66+
from kfp_tekton.compiler import TektonCompiler
67+
compiler = TektonCompiler()
68+
compiler.produce_taskspec = False
69+
compiler.compile(flipcoin_pipeline, __file__.replace('.py', '.yaml'))

sdk/python/kfp_tekton/compiler/compiler.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import collections
2727
from os import environ as env
2828
from typing import Callable, List, Text, Dict, Any
29+
import hashlib
2930

3031
import yaml
3132
# Kubeflow Pipeline imports
@@ -122,6 +123,7 @@ def __init__(self, **kwargs):
122123
# Input and output artifacts are hash maps for metadata tracking.
123124
# artifact_items is the artifact dependency map
124125
# loops_pipeline recorde the loop tasks information for each loops
126+
# produce_taskspec Produces task spec as part of Tekton pipelineRuns
125127
self.input_artifacts = {}
126128
self.output_artifacts = {}
127129
self.artifact_items = {}
@@ -134,6 +136,7 @@ def __init__(self, **kwargs):
134136
self.pipeline_annotations = {}
135137
self.tekton_inline_spec = True
136138
self.resource_in_separate_yaml = False
139+
self.produce_taskspec = True
137140
super().__init__(**kwargs)
138141

139142
def _set_pipeline_conf(self, tekton_pipeline_conf: TektonPipelineConf):
@@ -1431,7 +1434,46 @@ def _create_and_write_workflow(self,
14311434
workflow['metadata']['annotations']['tekton.dev/resource_templates'] = json.dumps(loop_package_annotations,
14321435
sort_keys=True)
14331436
# Need to compiles after all the CRs being processed.
1437+
# Convert taskspec into task templates if specified.
1438+
if not self.produce_taskspec:
1439+
component_sha = {}
1440+
for task in workflow['spec']['pipelineSpec']['tasks']:
1441+
if task.get('taskSpec'):
1442+
component_spec_digest = hashlib.sha1(json.dumps(task['taskSpec'], sort_keys=True).encode()).hexdigest()
1443+
if component_spec_digest not in component_sha.keys():
1444+
task_template = {}
1445+
task_template['metadata'] = {}
1446+
if task['taskSpec'].get('metadata', None):
1447+
task_template['metadata'] = task['taskSpec'].pop('metadata', None)
1448+
if task['taskSpec'].get('apiVersion', None) and task['taskSpec'].get('kind', None):
1449+
task_template['apiVersion'] = task['taskSpec']['apiVersion']
1450+
task_template['kind'] = task['taskSpec']['kind']
1451+
else:
1452+
task_template['apiVersion'] = tekton_api_version
1453+
task_template['kind'] = 'Task'
1454+
task_template['spec'] = task['taskSpec']
1455+
task_template['metadata']['name'] = component_spec_digest
1456+
component_sha[component_spec_digest] = task_template
1457+
task.pop("taskSpec", None)
1458+
task['taskRef'] = {'name': component_spec_digest}
1459+
# Output task templates into individual files if specified, else append task templates to annotations
1460+
if self.resource_in_separate_yaml:
1461+
for key, value in component_sha.items():
1462+
TektonCompiler._write_workflow(workflow=value,
1463+
package_path=os.path.splitext(package_path)[0] +
1464+
key + '.yaml')
1465+
else:
1466+
resource_templates = workflow['metadata']['annotations'].get('tekton.dev/resource_templates', [])
1467+
if resource_templates:
1468+
resource_templates = json.loads(resource_templates)
1469+
for value in component_sha.values():
1470+
resource_templates.append(value)
1471+
if resource_templates:
1472+
workflow['metadata']['annotations']['tekton.dev/resource_templates'] = json.dumps(resource_templates,
1473+
sort_keys=True)
1474+
14341475
TektonCompiler._write_workflow(workflow=workflow, package_path=package_path) # Tekton change
1476+
14351477
# Separate custom task CR from the main workflow
14361478
for i in range(len(self.custom_task_crs)):
14371479
TektonCompiler._write_workflow(workflow=self.custom_task_crs[i],

0 commit comments

Comments
 (0)