We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[v2compat] configurable default pipeline root
Quoted from https://github.com/kubeflow/pipelines/issues/4649#issuecomment-844035914
Blocks https://github.com/kubeflow/pipelines/issues/5680

> FYI, KFP v2 compatible mode has been released, see documentation: https://www.kubeflow.org/docs/components/pipelines/sdk/v2/.
> 
> It doesn't support artifact repository configuration, this is one of the things we want to support too. So I'm posting early thoughts on this related issue.
> 
> Let me first try to summarize requirements for configuring artifact repositories for both KFP v2 compatible and v2.
> 
> ## Object store specific credentials requirements
> For GCS, AWS S3, we suggest setting up credentials, so that they represent identity of the pipeline step, so that not only artifact upload/download, calls to other Cloud services should also use the same credentials. For this reason, we don't recommend setting credentials in artifact repository config. The suggestion is to configure the identity transparently if possible using GCP workload identity or AWS IRSA. If credentials are really necessary, they can be configured using pipeline DSL via [kfp.gcp.use_gcp_secret](https://kubeflow-pipelines.readthedocs.io/en/latest/source/kfp.extensions.html#kfp.gcp.use_gcp_secret) or [kfp.aws.use_aws_secret](https://kubeflow-pipelines.readthedocs.io/en/latest/source/kfp.extensions.html#kfp.aws.use_aws_secret) etc. These principles should apply to other Cloud Providers that has credentials that can be used with all its services.
> 
> For on-prem object store like MinIO, the credentials do not represent an identity, they are only used to access a specified object store instance. Therefore, it's reasonable to include them in artifact repository config.
> 
> ## In summary
> * For GCS, only pipeline root needs to be configurable.
> * For AWS S3, besides pipeline root, we also need region, endpoint etc to be configurable.
> * For MinIO or similar on-prem object stores, besides pipeline root, we also need endpoint, credentials to be configurable.
> 
> We cannot implement a spec for every possible object stores, so likely we should use the same spec as what [Go CDK](https://gocloud.dev/) supports or depend on cloud provider contributions.
> 
> Go CDK supports provider specific query params to configure some things other than object key, so we might consider adopting these query params, so that pipeline root can be more expressive, so we might not need other configurations.
> e.g. for S3, it's possible to configure region via a query param: https://gocloud.dev/howto/blob/#s3
> 
> ```
> s3://my-bucket?region=us-west-1
> ```
> 
> ## How we configure pipeline root, other configs and credentials?
> Ideally, pipeline root can include all other configs, so that we can uniquely identify an artifact.
> Ideally, credentials should be configurable transparently.
> 
> When both ideal requirements are met, we only need to support namespace level default pipeline root. All other configurations can be done by specifying different pipeline roots.
> 
> However, now MinIO violates the requirement that credentials can be configured transparently. Therefore, we need a mechanism to either
> 
> * configure which credentials should be used with which pipeline root (probably, write rules like which pipeline_root prefix/query param should use which credentials)
> * or configure credentials with pipeline root together as artifact repository (but then we should specify artifact repos, not pipeline roots)
> * or ask users to configure credentials separately from pipeline_root
> 
> We probably need more thoughts on the exact config format, this seems like a complex problem.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py`
Content:
```
1 # Copyright 2020-2021 The Kubeflow Authors
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 http.server import BaseHTTPRequestHandler, HTTPServer
16 import json
17 import os
18 import base64
19 
20 kfp_version = os.environ["KFP_VERSION"]
21 disable_istio_sidecar = os.environ.get("DISABLE_ISTIO_SIDECAR") == "true"
22 mlpipeline_minio_access_key = base64.b64encode(
23     bytes(os.environ.get("MINIO_ACCESS_KEY"), 'utf-8')).decode('utf-8')
24 mlpipeline_minio_secret_key = base64.b64encode(
25     bytes(os.environ.get("MINIO_SECRET_KEY"), 'utf-8')).decode('utf-8')
26 
27 
28 class Controller(BaseHTTPRequestHandler):
29     def sync(self, parent, children):
30         pipeline_enabled = parent.get("metadata", {}).get(
31             "labels", {}).get("pipelines.kubeflow.org/enabled")
32 
33         if pipeline_enabled != "true":
34             return {"status": {}, "children": []}
35 
36         # Compute status based on observed state.
37         desired_status = {
38             "kubeflow-pipelines-ready": \
39                 len(children["Secret.v1"]) == 1 and \
40                 len(children["ConfigMap.v1"]) == 1 and \
41                 len(children["Deployment.apps/v1"]) == 2 and \
42                 len(children["Service.v1"]) == 2 and \
43                 len(children["DestinationRule.networking.istio.io/v1alpha3"]) == 1 and \
44                 len(children["AuthorizationPolicy.security.istio.io/v1beta1"]) == 1 and \
45                 "True" or "False"
46         }
47 
48         # Generate the desired child object(s).
49         # parent is a namespace
50         namespace = parent.get("metadata", {}).get("name")
51         desired_resources = [
52             {
53                 "apiVersion": "v1",
54                 "kind": "ConfigMap",
55                 "metadata": {
56                     "name": "metadata-grpc-configmap",
57                     "namespace": namespace,
58                 },
59                 "data": {
60                     "METADATA_GRPC_SERVICE_HOST":
61                     "metadata-grpc-service.kubeflow",
62                     "METADATA_GRPC_SERVICE_PORT": "8080",
63                 },
64             },
65             # Visualization server related manifests below
66             {
67                 "apiVersion": "apps/v1",
68                 "kind": "Deployment",
69                 "metadata": {
70                     "labels": {
71                         "app": "ml-pipeline-visualizationserver"
72                     },
73                     "name": "ml-pipeline-visualizationserver",
74                     "namespace": namespace,
75                 },
76                 "spec": {
77                     "selector": {
78                         "matchLabels": {
79                             "app": "ml-pipeline-visualizationserver"
80                         },
81                     },
82                     "template": {
83                         "metadata": {
84                             "labels": {
85                                 "app": "ml-pipeline-visualizationserver"
86                             },
87                             "annotations": disable_istio_sidecar and {
88                                 "sidecar.istio.io/inject": "false"
89                             } or {},
90                         },
91                         "spec": {
92                             "containers": [{
93                                 "image":
94                                 "gcr.io/ml-pipeline/visualization-server:" +
95                                 kfp_version,
96                                 "imagePullPolicy":
97                                 "IfNotPresent",
98                                 "name":
99                                 "ml-pipeline-visualizationserver",
100                                 "ports": [{
101                                     "containerPort": 8888
102                                 }],
103                                 "resources": {
104                                     "requests": {
105                                         "cpu": "50m",
106                                         "memory": "200Mi"
107                                     },
108                                     "limits": {
109                                         "cpu": "500m",
110                                         "memory": "1Gi"
111                                     },
112                                 }
113                             }],
114                             "serviceAccountName":
115                             "default-editor",
116                         },
117                     },
118                 },
119             },
120             {
121                 "apiVersion": "networking.istio.io/v1alpha3",
122                 "kind": "DestinationRule",
123                 "metadata": {
124                     "name": "ml-pipeline-visualizationserver",
125                     "namespace": namespace,
126                 },
127                 "spec": {
128                     "host": "ml-pipeline-visualizationserver",
129                     "trafficPolicy": {
130                         "tls": {
131                             "mode": "ISTIO_MUTUAL"
132                         }
133                     }
134                 }
135             },
136             {
137                 "apiVersion": "security.istio.io/v1beta1",
138                 "kind": "AuthorizationPolicy",
139                 "metadata": {
140                     "name": "ml-pipeline-visualizationserver",
141                     "namespace": namespace,
142                 },
143                 "spec": {
144                     "selector": {
145                         "matchLabels": {
146                             "app": "ml-pipeline-visualizationserver"
147                         }
148                     },
149                     "rules": [{
150                         "from": [{
151                             "source": {
152                                 "principals": ["cluster.local/ns/kubeflow/sa/ml-pipeline"]
153                             }
154                         }]
155                     }]
156                 }
157             },
158             {
159                 "apiVersion": "v1",
160                 "kind": "Service",
161                 "metadata": {
162                     "name": "ml-pipeline-visualizationserver",
163                     "namespace": namespace,
164                 },
165                 "spec": {
166                     "ports": [{
167                         "name": "http",
168                         "port": 8888,
169                         "protocol": "TCP",
170                         "targetPort": 8888,
171                     }],
172                     "selector": {
173                         "app": "ml-pipeline-visualizationserver",
174                     },
175                 },
176             },
177             # Artifact fetcher related resources below.
178             {
179                 "apiVersion": "apps/v1",
180                 "kind": "Deployment",
181                 "metadata": {
182                     "labels": {
183                         "app": "ml-pipeline-ui-artifact"
184                     },
185                     "name": "ml-pipeline-ui-artifact",
186                     "namespace": namespace,
187                 },
188                 "spec": {
189                     "selector": {
190                         "matchLabels": {
191                             "app": "ml-pipeline-ui-artifact"
192                         }
193                     },
194                     "template": {
195                         "metadata": {
196                             "labels": {
197                                 "app": "ml-pipeline-ui-artifact"
198                             },
199                             "annotations": disable_istio_sidecar and {
200                                 "sidecar.istio.io/inject": "false"
201                             } or {},
202                         },
203                         "spec": {
204                             "containers": [{
205                                 "name":
206                                 "ml-pipeline-ui-artifact",
207                                 "image":
208                                 "gcr.io/ml-pipeline/frontend:" + kfp_version,
209                                 "imagePullPolicy":
210                                 "IfNotPresent",
211                                 "ports": [{
212                                     "containerPort": 3000
213                                 }],
214                                 "resources": {
215                                     "requests": {
216                                         "cpu": "10m",
217                                         "memory": "70Mi"
218                                     },
219                                     "limits": {
220                                         "cpu": "100m",
221                                         "memory": "500Mi"
222                                     },
223                                 }
224                             }],
225                             "serviceAccountName":
226                             "default-editor"
227                         }
228                     }
229                 }
230             },
231             {
232                 "apiVersion": "v1",
233                 "kind": "Service",
234                 "metadata": {
235                     "name": "ml-pipeline-ui-artifact",
236                     "namespace": namespace,
237                     "labels": {
238                         "app": "ml-pipeline-ui-artifact"
239                     }
240                 },
241                 "spec": {
242                     "ports": [{
243                         "name":
244                         "http",  # name is required to let istio understand request protocol
245                         "port": 80,
246                         "protocol": "TCP",
247                         "targetPort": 3000
248                     }],
249                     "selector": {
250                         "app": "ml-pipeline-ui-artifact"
251                     }
252                 }
253             },
254         ]
255         print('Received request:', parent)
256         print('Desired resources except secrets:', desired_resources)
257         # Moved after the print argument because this is sensitive data.
258         desired_resources.append({
259             "apiVersion": "v1",
260             "kind": "Secret",
261             "metadata": {
262                 "name": "mlpipeline-minio-artifact",
263                 "namespace": namespace,
264             },
265             "data": {
266                 "accesskey": mlpipeline_minio_access_key,
267                 "secretkey": mlpipeline_minio_secret_key,
268             },
269         })
270 
271         return {"status": desired_status, "children": desired_resources}
272 
273     def do_POST(self):
274         # Serve the sync() function as a JSON webhook.
275         observed = json.loads(
276             self.rfile.read(int(self.headers.get("content-length"))))
277         desired = self.sync(observed["parent"], observed["children"])
278 
279         self.send_response(200)
280         self.send_header("Content-type", "application/json")
281         self.end_headers()
282         self.wfile.write(bytes(json.dumps(desired), 'utf-8'))
283 
284 
285 HTTPServer(("", 8080), Controller).serve_forever()
286
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py
--- a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py
+++ b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py
@@ -18,6 +18,8 @@
 import base64
 
 kfp_version = os.environ["KFP_VERSION"]
+# KFP_DEFAULT_PIPELINE_ROOT is optional
+kfp_default_pipeline_root = os.environ.get("KFP_DEFAULT_PIPELINE_ROOT")
 disable_istio_sidecar = os.environ.get("DISABLE_ISTIO_SIDECAR") == "true"
 mlpipeline_minio_access_key = base64.b64encode(
     bytes(os.environ.get("MINIO_ACCESS_KEY"), 'utf-8')).decode('utf-8')
@@ -27,17 +29,35 @@
 
 class Controller(BaseHTTPRequestHandler):
     def sync(self, parent, children):
+        # parent is a namespace
+        namespace = parent.get("metadata", {}).get("name")
         pipeline_enabled = parent.get("metadata", {}).get(
             "labels", {}).get("pipelines.kubeflow.org/enabled")
 
         if pipeline_enabled != "true":
             return {"status": {}, "children": []}
 
+        desired_configmap_count = 1
+        desired_resources = []
+        if kfp_default_pipeline_root:
+            desired_configmap_count = 2
+            desired_resources += [{
+                "apiVersion": "v1",
+                "kind": "ConfigMap",
+                "metadata": {
+                    "name": "kfp-launcher",
+                    "namespace": namespace,
+                },
+                "data": {
+                    "defaultPipelineRoot": kfp_default_pipeline_root,
+                },
+            }]
+
         # Compute status based on observed state.
         desired_status = {
             "kubeflow-pipelines-ready": \
                 len(children["Secret.v1"]) == 1 and \
-                len(children["ConfigMap.v1"]) == 1 and \
+                len(children["ConfigMap.v1"]) == desired_configmap_count and \
                 len(children["Deployment.apps/v1"]) == 2 and \
                 len(children["Service.v1"]) == 2 and \
                 len(children["DestinationRule.networking.istio.io/v1alpha3"]) == 1 and \
@@ -46,9 +66,7 @@
         }
 
         # Generate the desired child object(s).
-        # parent is a namespace
-        namespace = parent.get("metadata", {}).get("name")
-        desired_resources = [
+        desired_resources += [
             {
                 "apiVersion": "v1",
                 "kind": "ConfigMap",

{"golden_diff": "diff --git a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py\n--- a/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py\n+++ b/manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py\n@@ -18,6 +18,8 @@\n import base64\n \n kfp_version = os.environ[\"KFP_VERSION\"]\n+# KFP_DEFAULT_PIPELINE_ROOT is optional\n+kfp_default_pipeline_root = os.environ.get(\"KFP_DEFAULT_PIPELINE_ROOT\")\n disable_istio_sidecar = os.environ.get(\"DISABLE_ISTIO_SIDECAR\") == \"true\"\n mlpipeline_minio_access_key = base64.b64encode(\n     bytes(os.environ.get(\"MINIO_ACCESS_KEY\"), 'utf-8')).decode('utf-8')\n@@ -27,17 +29,35 @@\n \n class Controller(BaseHTTPRequestHandler):\n     def sync(self, parent, children):\n+        # parent is a namespace\n+        namespace = parent.get(\"metadata\", {}).get(\"name\")\n         pipeline_enabled = parent.get(\"metadata\", {}).get(\n             \"labels\", {}).get(\"pipelines.kubeflow.org/enabled\")\n \n         if pipeline_enabled != \"true\":\n             return {\"status\": {}, \"children\": []}\n \n+        desired_configmap_count = 1\n+        desired_resources = []\n+        if kfp_default_pipeline_root:\n+            desired_configmap_count = 2\n+            desired_resources += [{\n+                \"apiVersion\": \"v1\",\n+                \"kind\": \"ConfigMap\",\n+                \"metadata\": {\n+                    \"name\": \"kfp-launcher\",\n+                    \"namespace\": namespace,\n+                },\n+                \"data\": {\n+                    \"defaultPipelineRoot\": kfp_default_pipeline_root,\n+                },\n+            }]\n+\n         # Compute status based on observed state.\n         desired_status = {\n             \"kubeflow-pipelines-ready\": \\\n                 len(children[\"Secret.v1\"]) == 1 and \\\n-                len(children[\"ConfigMap.v1\"]) == 1 and \\\n+                len(children[\"ConfigMap.v1\"]) == desired_configmap_count and \\\n                 len(children[\"Deployment.apps/v1\"]) == 2 and \\\n                 len(children[\"Service.v1\"]) == 2 and \\\n                 len(children[\"DestinationRule.networking.istio.io/v1alpha3\"]) == 1 and \\\n@@ -46,9 +66,7 @@\n         }\n \n         # Generate the desired child object(s).\n-        # parent is a namespace\n-        namespace = parent.get(\"metadata\", {}).get(\"name\")\n-        desired_resources = [\n+        desired_resources += [\n             {\n                 \"apiVersion\": \"v1\",\n                 \"kind\": \"ConfigMap\",\n", "issue": "[v2compat] configurable default pipeline root\nQuoted from https://github.com/kubeflow/pipelines/issues/4649#issuecomment-844035914\r\nBlocks https://github.com/kubeflow/pipelines/issues/5680\r\n\r\n> FYI, KFP v2 compatible mode has been released, see documentation: https://www.kubeflow.org/docs/components/pipelines/sdk/v2/.\r\n> \r\n> It doesn't support artifact repository configuration, this is one of the things we want to support too. So I'm posting early thoughts on this related issue.\r\n> \r\n> Let me first try to summarize requirements for configuring artifact repositories for both KFP v2 compatible and v2.\r\n> \r\n> ## Object store specific credentials requirements\r\n> For GCS, AWS S3, we suggest setting up credentials, so that they represent identity of the pipeline step, so that not only artifact upload/download, calls to other Cloud services should also use the same credentials. For this reason, we don't recommend setting credentials in artifact repository config. The suggestion is to configure the identity transparently if possible using GCP workload identity or AWS IRSA. If credentials are really necessary, they can be configured using pipeline DSL via [kfp.gcp.use_gcp_secret](https://kubeflow-pipelines.readthedocs.io/en/latest/source/kfp.extensions.html#kfp.gcp.use_gcp_secret) or [kfp.aws.use_aws_secret](https://kubeflow-pipelines.readthedocs.io/en/latest/source/kfp.extensions.html#kfp.aws.use_aws_secret) etc. These principles should apply to other Cloud Providers that has credentials that can be used with all its services.\r\n> \r\n> For on-prem object store like MinIO, the credentials do not represent an identity, they are only used to access a specified object store instance. Therefore, it's reasonable to include them in artifact repository config.\r\n> \r\n> ## In summary\r\n> * For GCS, only pipeline root needs to be configurable.\r\n> * For AWS S3, besides pipeline root, we also need region, endpoint etc to be configurable.\r\n> * For MinIO or similar on-prem object stores, besides pipeline root, we also need endpoint, credentials to be configurable.\r\n> \r\n> We cannot implement a spec for every possible object stores, so likely we should use the same spec as what [Go CDK](https://gocloud.dev/) supports or depend on cloud provider contributions.\r\n> \r\n> Go CDK supports provider specific query params to configure some things other than object key, so we might consider adopting these query params, so that pipeline root can be more expressive, so we might not need other configurations.\r\n> e.g. for S3, it's possible to configure region via a query param: https://gocloud.dev/howto/blob/#s3\r\n> \r\n> ```\r\n> s3://my-bucket?region=us-west-1\r\n> ```\r\n> \r\n> ## How we configure pipeline root, other configs and credentials?\r\n> Ideally, pipeline root can include all other configs, so that we can uniquely identify an artifact.\r\n> Ideally, credentials should be configurable transparently.\r\n> \r\n> When both ideal requirements are met, we only need to support namespace level default pipeline root. All other configurations can be done by specifying different pipeline roots.\r\n> \r\n> However, now MinIO violates the requirement that credentials can be configured transparently. Therefore, we need a mechanism to either\r\n> \r\n> * configure which credentials should be used with which pipeline root (probably, write rules like which pipeline_root prefix/query param should use which credentials)\r\n> * or configure credentials with pipeline root together as artifact repository (but then we should specify artifact repos, not pipeline roots)\r\n> * or ask users to configure credentials separately from pipeline_root\r\n> \r\n> We probably need more thoughts on the exact config format, this seems like a complex problem.\r\n\r\n\n", "before_files": [{"content": "# Copyright 2020-2021 The Kubeflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nimport json\nimport os\nimport base64\n\nkfp_version = os.environ[\"KFP_VERSION\"]\ndisable_istio_sidecar = os.environ.get(\"DISABLE_ISTIO_SIDECAR\") == \"true\"\nmlpipeline_minio_access_key = base64.b64encode(\n    bytes(os.environ.get(\"MINIO_ACCESS_KEY\"), 'utf-8')).decode('utf-8')\nmlpipeline_minio_secret_key = base64.b64encode(\n    bytes(os.environ.get(\"MINIO_SECRET_KEY\"), 'utf-8')).decode('utf-8')\n\n\nclass Controller(BaseHTTPRequestHandler):\n    def sync(self, parent, children):\n        pipeline_enabled = parent.get(\"metadata\", {}).get(\n            \"labels\", {}).get(\"pipelines.kubeflow.org/enabled\")\n\n        if pipeline_enabled != \"true\":\n            return {\"status\": {}, \"children\": []}\n\n        # Compute status based on observed state.\n        desired_status = {\n            \"kubeflow-pipelines-ready\": \\\n                len(children[\"Secret.v1\"]) == 1 and \\\n                len(children[\"ConfigMap.v1\"]) == 1 and \\\n                len(children[\"Deployment.apps/v1\"]) == 2 and \\\n                len(children[\"Service.v1\"]) == 2 and \\\n                len(children[\"DestinationRule.networking.istio.io/v1alpha3\"]) == 1 and \\\n                len(children[\"AuthorizationPolicy.security.istio.io/v1beta1\"]) == 1 and \\\n                \"True\" or \"False\"\n        }\n\n        # Generate the desired child object(s).\n        # parent is a namespace\n        namespace = parent.get(\"metadata\", {}).get(\"name\")\n        desired_resources = [\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"ConfigMap\",\n                \"metadata\": {\n                    \"name\": \"metadata-grpc-configmap\",\n                    \"namespace\": namespace,\n                },\n                \"data\": {\n                    \"METADATA_GRPC_SERVICE_HOST\":\n                    \"metadata-grpc-service.kubeflow\",\n                    \"METADATA_GRPC_SERVICE_PORT\": \"8080\",\n                },\n            },\n            # Visualization server related manifests below\n            {\n                \"apiVersion\": \"apps/v1\",\n                \"kind\": \"Deployment\",\n                \"metadata\": {\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-visualizationserver\"\n                    },\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-visualizationserver\"\n                        },\n                    },\n                    \"template\": {\n                        \"metadata\": {\n                            \"labels\": {\n                                \"app\": \"ml-pipeline-visualizationserver\"\n                            },\n                            \"annotations\": disable_istio_sidecar and {\n                                \"sidecar.istio.io/inject\": \"false\"\n                            } or {},\n                        },\n                        \"spec\": {\n                            \"containers\": [{\n                                \"image\":\n                                \"gcr.io/ml-pipeline/visualization-server:\" +\n                                kfp_version,\n                                \"imagePullPolicy\":\n                                \"IfNotPresent\",\n                                \"name\":\n                                \"ml-pipeline-visualizationserver\",\n                                \"ports\": [{\n                                    \"containerPort\": 8888\n                                }],\n                                \"resources\": {\n                                    \"requests\": {\n                                        \"cpu\": \"50m\",\n                                        \"memory\": \"200Mi\"\n                                    },\n                                    \"limits\": {\n                                        \"cpu\": \"500m\",\n                                        \"memory\": \"1Gi\"\n                                    },\n                                }\n                            }],\n                            \"serviceAccountName\":\n                            \"default-editor\",\n                        },\n                    },\n                },\n            },\n            {\n                \"apiVersion\": \"networking.istio.io/v1alpha3\",\n                \"kind\": \"DestinationRule\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"host\": \"ml-pipeline-visualizationserver\",\n                    \"trafficPolicy\": {\n                        \"tls\": {\n                            \"mode\": \"ISTIO_MUTUAL\"\n                        }\n                    }\n                }\n            },\n            {\n                \"apiVersion\": \"security.istio.io/v1beta1\",\n                \"kind\": \"AuthorizationPolicy\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-visualizationserver\"\n                        }\n                    },\n                    \"rules\": [{\n                        \"from\": [{\n                            \"source\": {\n                                \"principals\": [\"cluster.local/ns/kubeflow/sa/ml-pipeline\"]\n                            }\n                        }]\n                    }]\n                }\n            },\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"Service\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"ports\": [{\n                        \"name\": \"http\",\n                        \"port\": 8888,\n                        \"protocol\": \"TCP\",\n                        \"targetPort\": 8888,\n                    }],\n                    \"selector\": {\n                        \"app\": \"ml-pipeline-visualizationserver\",\n                    },\n                },\n            },\n            # Artifact fetcher related resources below.\n            {\n                \"apiVersion\": \"apps/v1\",\n                \"kind\": \"Deployment\",\n                \"metadata\": {\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    },\n                    \"name\": \"ml-pipeline-ui-artifact\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-ui-artifact\"\n                        }\n                    },\n                    \"template\": {\n                        \"metadata\": {\n                            \"labels\": {\n                                \"app\": \"ml-pipeline-ui-artifact\"\n                            },\n                            \"annotations\": disable_istio_sidecar and {\n                                \"sidecar.istio.io/inject\": \"false\"\n                            } or {},\n                        },\n                        \"spec\": {\n                            \"containers\": [{\n                                \"name\":\n                                \"ml-pipeline-ui-artifact\",\n                                \"image\":\n                                \"gcr.io/ml-pipeline/frontend:\" + kfp_version,\n                                \"imagePullPolicy\":\n                                \"IfNotPresent\",\n                                \"ports\": [{\n                                    \"containerPort\": 3000\n                                }],\n                                \"resources\": {\n                                    \"requests\": {\n                                        \"cpu\": \"10m\",\n                                        \"memory\": \"70Mi\"\n                                    },\n                                    \"limits\": {\n                                        \"cpu\": \"100m\",\n                                        \"memory\": \"500Mi\"\n                                    },\n                                }\n                            }],\n                            \"serviceAccountName\":\n                            \"default-editor\"\n                        }\n                    }\n                }\n            },\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"Service\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-ui-artifact\",\n                    \"namespace\": namespace,\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    }\n                },\n                \"spec\": {\n                    \"ports\": [{\n                        \"name\":\n                        \"http\",  # name is required to let istio understand request protocol\n                        \"port\": 80,\n                        \"protocol\": \"TCP\",\n                        \"targetPort\": 3000\n                    }],\n                    \"selector\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    }\n                }\n            },\n        ]\n        print('Received request:', parent)\n        print('Desired resources except secrets:', desired_resources)\n        # Moved after the print argument because this is sensitive data.\n        desired_resources.append({\n            \"apiVersion\": \"v1\",\n            \"kind\": \"Secret\",\n            \"metadata\": {\n                \"name\": \"mlpipeline-minio-artifact\",\n                \"namespace\": namespace,\n            },\n            \"data\": {\n                \"accesskey\": mlpipeline_minio_access_key,\n                \"secretkey\": mlpipeline_minio_secret_key,\n            },\n        })\n\n        return {\"status\": desired_status, \"children\": desired_resources}\n\n    def do_POST(self):\n        # Serve the sync() function as a JSON webhook.\n        observed = json.loads(\n            self.rfile.read(int(self.headers.get(\"content-length\"))))\n        desired = self.sync(observed[\"parent\"], observed[\"children\"])\n\n        self.send_response(200)\n        self.send_header(\"Content-type\", \"application/json\")\n        self.end_headers()\n        self.wfile.write(bytes(json.dumps(desired), 'utf-8'))\n\n\nHTTPServer((\"\", 8080), Controller).serve_forever()\n", "path": "manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py"}], "after_files": [{"content": "# Copyright 2020-2021 The Kubeflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nimport json\nimport os\nimport base64\n\nkfp_version = os.environ[\"KFP_VERSION\"]\n# KFP_DEFAULT_PIPELINE_ROOT is optional\nkfp_default_pipeline_root = os.environ.get(\"KFP_DEFAULT_PIPELINE_ROOT\")\ndisable_istio_sidecar = os.environ.get(\"DISABLE_ISTIO_SIDECAR\") == \"true\"\nmlpipeline_minio_access_key = base64.b64encode(\n    bytes(os.environ.get(\"MINIO_ACCESS_KEY\"), 'utf-8')).decode('utf-8')\nmlpipeline_minio_secret_key = base64.b64encode(\n    bytes(os.environ.get(\"MINIO_SECRET_KEY\"), 'utf-8')).decode('utf-8')\n\n\nclass Controller(BaseHTTPRequestHandler):\n    def sync(self, parent, children):\n        # parent is a namespace\n        namespace = parent.get(\"metadata\", {}).get(\"name\")\n        pipeline_enabled = parent.get(\"metadata\", {}).get(\n            \"labels\", {}).get(\"pipelines.kubeflow.org/enabled\")\n\n        if pipeline_enabled != \"true\":\n            return {\"status\": {}, \"children\": []}\n\n        desired_configmap_count = 1\n        desired_resources = []\n        if kfp_default_pipeline_root:\n            desired_configmap_count = 2\n            desired_resources += [{\n                \"apiVersion\": \"v1\",\n                \"kind\": \"ConfigMap\",\n                \"metadata\": {\n                    \"name\": \"kfp-launcher\",\n                    \"namespace\": namespace,\n                },\n                \"data\": {\n                    \"defaultPipelineRoot\": kfp_default_pipeline_root,\n                },\n            }]\n\n        # Compute status based on observed state.\n        desired_status = {\n            \"kubeflow-pipelines-ready\": \\\n                len(children[\"Secret.v1\"]) == 1 and \\\n                len(children[\"ConfigMap.v1\"]) == desired_configmap_count and \\\n                len(children[\"Deployment.apps/v1\"]) == 2 and \\\n                len(children[\"Service.v1\"]) == 2 and \\\n                len(children[\"DestinationRule.networking.istio.io/v1alpha3\"]) == 1 and \\\n                len(children[\"AuthorizationPolicy.security.istio.io/v1beta1\"]) == 1 and \\\n                \"True\" or \"False\"\n        }\n\n        # Generate the desired child object(s).\n        desired_resources += [\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"ConfigMap\",\n                \"metadata\": {\n                    \"name\": \"metadata-grpc-configmap\",\n                    \"namespace\": namespace,\n                },\n                \"data\": {\n                    \"METADATA_GRPC_SERVICE_HOST\":\n                    \"metadata-grpc-service.kubeflow\",\n                    \"METADATA_GRPC_SERVICE_PORT\": \"8080\",\n                },\n            },\n            # Visualization server related manifests below\n            {\n                \"apiVersion\": \"apps/v1\",\n                \"kind\": \"Deployment\",\n                \"metadata\": {\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-visualizationserver\"\n                    },\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-visualizationserver\"\n                        },\n                    },\n                    \"template\": {\n                        \"metadata\": {\n                            \"labels\": {\n                                \"app\": \"ml-pipeline-visualizationserver\"\n                            },\n                            \"annotations\": disable_istio_sidecar and {\n                                \"sidecar.istio.io/inject\": \"false\"\n                            } or {},\n                        },\n                        \"spec\": {\n                            \"containers\": [{\n                                \"image\":\n                                \"gcr.io/ml-pipeline/visualization-server:\" +\n                                kfp_version,\n                                \"imagePullPolicy\":\n                                \"IfNotPresent\",\n                                \"name\":\n                                \"ml-pipeline-visualizationserver\",\n                                \"ports\": [{\n                                    \"containerPort\": 8888\n                                }],\n                                \"resources\": {\n                                    \"requests\": {\n                                        \"cpu\": \"50m\",\n                                        \"memory\": \"200Mi\"\n                                    },\n                                    \"limits\": {\n                                        \"cpu\": \"500m\",\n                                        \"memory\": \"1Gi\"\n                                    },\n                                }\n                            }],\n                            \"serviceAccountName\":\n                            \"default-editor\",\n                        },\n                    },\n                },\n            },\n            {\n                \"apiVersion\": \"networking.istio.io/v1alpha3\",\n                \"kind\": \"DestinationRule\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"host\": \"ml-pipeline-visualizationserver\",\n                    \"trafficPolicy\": {\n                        \"tls\": {\n                            \"mode\": \"ISTIO_MUTUAL\"\n                        }\n                    }\n                }\n            },\n            {\n                \"apiVersion\": \"security.istio.io/v1beta1\",\n                \"kind\": \"AuthorizationPolicy\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-visualizationserver\"\n                        }\n                    },\n                    \"rules\": [{\n                        \"from\": [{\n                            \"source\": {\n                                \"principals\": [\"cluster.local/ns/kubeflow/sa/ml-pipeline\"]\n                            }\n                        }]\n                    }]\n                }\n            },\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"Service\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-visualizationserver\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"ports\": [{\n                        \"name\": \"http\",\n                        \"port\": 8888,\n                        \"protocol\": \"TCP\",\n                        \"targetPort\": 8888,\n                    }],\n                    \"selector\": {\n                        \"app\": \"ml-pipeline-visualizationserver\",\n                    },\n                },\n            },\n            # Artifact fetcher related resources below.\n            {\n                \"apiVersion\": \"apps/v1\",\n                \"kind\": \"Deployment\",\n                \"metadata\": {\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    },\n                    \"name\": \"ml-pipeline-ui-artifact\",\n                    \"namespace\": namespace,\n                },\n                \"spec\": {\n                    \"selector\": {\n                        \"matchLabels\": {\n                            \"app\": \"ml-pipeline-ui-artifact\"\n                        }\n                    },\n                    \"template\": {\n                        \"metadata\": {\n                            \"labels\": {\n                                \"app\": \"ml-pipeline-ui-artifact\"\n                            },\n                            \"annotations\": disable_istio_sidecar and {\n                                \"sidecar.istio.io/inject\": \"false\"\n                            } or {},\n                        },\n                        \"spec\": {\n                            \"containers\": [{\n                                \"name\":\n                                \"ml-pipeline-ui-artifact\",\n                                \"image\":\n                                \"gcr.io/ml-pipeline/frontend:\" + kfp_version,\n                                \"imagePullPolicy\":\n                                \"IfNotPresent\",\n                                \"ports\": [{\n                                    \"containerPort\": 3000\n                                }],\n                                \"resources\": {\n                                    \"requests\": {\n                                        \"cpu\": \"10m\",\n                                        \"memory\": \"70Mi\"\n                                    },\n                                    \"limits\": {\n                                        \"cpu\": \"100m\",\n                                        \"memory\": \"500Mi\"\n                                    },\n                                }\n                            }],\n                            \"serviceAccountName\":\n                            \"default-editor\"\n                        }\n                    }\n                }\n            },\n            {\n                \"apiVersion\": \"v1\",\n                \"kind\": \"Service\",\n                \"metadata\": {\n                    \"name\": \"ml-pipeline-ui-artifact\",\n                    \"namespace\": namespace,\n                    \"labels\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    }\n                },\n                \"spec\": {\n                    \"ports\": [{\n                        \"name\":\n                        \"http\",  # name is required to let istio understand request protocol\n                        \"port\": 80,\n                        \"protocol\": \"TCP\",\n                        \"targetPort\": 3000\n                    }],\n                    \"selector\": {\n                        \"app\": \"ml-pipeline-ui-artifact\"\n                    }\n                }\n            },\n        ]\n        print('Received request:', parent)\n        print('Desired resources except secrets:', desired_resources)\n        # Moved after the print argument because this is sensitive data.\n        desired_resources.append({\n            \"apiVersion\": \"v1\",\n            \"kind\": \"Secret\",\n            \"metadata\": {\n                \"name\": \"mlpipeline-minio-artifact\",\n                \"namespace\": namespace,\n            },\n            \"data\": {\n                \"accesskey\": mlpipeline_minio_access_key,\n                \"secretkey\": mlpipeline_minio_secret_key,\n            },\n        })\n\n        return {\"status\": desired_status, \"children\": desired_resources}\n\n    def do_POST(self):\n        # Serve the sync() function as a JSON webhook.\n        observed = json.loads(\n            self.rfile.read(int(self.headers.get(\"content-length\"))))\n        desired = self.sync(observed[\"parent\"], observed[\"children\"])\n\n        self.send_response(200)\n        self.send_header(\"Content-type\", \"application/json\")\n        self.end_headers()\n        self.wfile.write(bytes(json.dumps(desired), 'utf-8'))\n\n\nHTTPServer((\"\", 8080), Controller).serve_forever()\n", "path": "manifests/kustomize/base/installs/multi-user/pipelines-profile-controller/sync.py"}]}