diff --git a/appstore/tycho/template/cluster/jupyter-ds/clusterrole.yaml b/appstore/tycho/template/cluster/jupyter-ds/clusterrole.yaml new file mode 100644 index 00000000..8360408b --- /dev/null +++ b/appstore/tycho/template/cluster/jupyter-ds/clusterrole.yaml @@ -0,0 +1,10 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ system.system_name }} + labels: + name: {{ system.system_name }} +rules: +- apiGroups: [""] + resources: ["pods", "deployments"] + verbs: ["get", "watch", "list"] diff --git a/appstore/tycho/template/cluster/nextflow/clusterrole.yaml b/appstore/tycho/template/cluster/nextflow/clusterrole.yaml new file mode 100644 index 00000000..a63fa54f --- /dev/null +++ b/appstore/tycho/template/cluster/nextflow/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ system.system_name }} + labels: + name: {{ system.system_name }} + tycho-guid: {{ system.identifier }} +rules: +- apiGroups: [""] + resources: ["pods", "deployments"] + verbs: ["get", "watch", "list"] diff --git a/appstore/tycho/template/cluster/nginx/clusterrole.yaml b/appstore/tycho/template/cluster/nginx/clusterrole.yaml new file mode 100644 index 00000000..8360408b --- /dev/null +++ b/appstore/tycho/template/cluster/nginx/clusterrole.yaml @@ -0,0 +1,10 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ system.system_name }} + labels: + name: {{ system.system_name }} +rules: +- apiGroups: [""] + resources: ["pods", "deployments"] + verbs: ["get", "watch", "list"] diff --git a/appstore/tycho/template/clusterrole.yaml b/appstore/tycho/template/clusterrole.yaml new file mode 100644 index 00000000..8360408b --- /dev/null +++ b/appstore/tycho/template/clusterrole.yaml @@ -0,0 +1,10 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ system.system_name }} + labels: + name: {{ system.system_name }} +rules: +- apiGroups: [""] + resources: ["pods", "deployments"] + verbs: ["get", "watch", "list"] diff --git a/appstore/tycho/template/clusterrolebinding.yaml b/appstore/tycho/template/clusterrolebinding.yaml new file mode 100644 index 00000000..ededa5c6 --- /dev/null +++ b/appstore/tycho/template/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ system.system_name }}-global-2 + labels: + name: {{ system.system_name }} +#subjects: +#- kind: Group +# name: manager +# apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: {{ system.system_name }} + apiGroup: rbac.authorization.k8s.io diff --git a/appstore/tycho/template/jupyter-ds/clusterrolebinding.yaml b/appstore/tycho/template/jupyter-ds/clusterrolebinding.yaml new file mode 100644 index 00000000..ededa5c6 --- /dev/null +++ b/appstore/tycho/template/jupyter-ds/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ system.system_name }}-global-2 + labels: + name: {{ system.system_name }} +#subjects: +#- kind: Group +# name: manager +# apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: {{ system.system_name }} + apiGroup: rbac.authorization.k8s.io diff --git a/appstore/tycho/template/mapping.yaml b/appstore/tycho/template/mapping.yaml new file mode 100644 index 00000000..a3122ad0 --- /dev/null +++ b/appstore/tycho/template/mapping.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: ambassador/v1 +kind: Mapping +name: {{system.name}}-mapping +host: helx-app-commonsshare-org +prefix: {{system.system_name}}/{{system.username}}/{{system.identifier}} +headers: + remote_user: {{system.username}} +service: {{system.name}}:{{system.system_port}} +bypass_auth: true +timeout_ms: 300000 diff --git a/appstore/tycho/template/nextflow/clusterrolebinding.yaml b/appstore/tycho/template/nextflow/clusterrolebinding.yaml new file mode 100644 index 00000000..35f3e4e5 --- /dev/null +++ b/appstore/tycho/template/nextflow/clusterrolebinding.yaml @@ -0,0 +1,32 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: view-global + labels: + name: {{ system.system_name }} + tycho-guid: {{ system.identifier }} +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: view + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: edit-global + labels: + name: {{ system.system_name }} + tycho-guid: {{ system.identifier }} +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: edit + apiGroup: rbac.authorization.k8s.io + diff --git a/appstore/tycho/template/nginx/clusterrolebinding.yaml b/appstore/tycho/template/nginx/clusterrolebinding.yaml new file mode 100644 index 00000000..fc5db67f --- /dev/null +++ b/appstore/tycho/template/nginx/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ system.system_name }}-global + labels: + name: {{ system.system_name }} +#subjects: +#- kind: Group +# name: manager +# apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: {{ system.system_name }} + apiGroup: rbac.authorization.k8s.io diff --git a/appstore/tycho/template/patch.yaml b/appstore/tycho/template/patch.yaml new file mode 100644 index 00000000..95b0cbb7 --- /dev/null +++ b/appstore/tycho/template/patch.yaml @@ -0,0 +1,28 @@ +{% if system_modify.patch %} +spec: + template: + {% if system_modify.labels|length > 0 %} + metadata: + labels: + {% for key, value in system_modify.labels.items() %} + {{ key }}: {{ value }} + {% endfor %} + {% endif %} + {% if system_modify.resources|length > 0 %} + spec: + containers: + {% for container in system_modify.containers %} + - resources: + limits: + {% for key, value in system_modify.resources.items() %} + {{ key }}: {{ value }} + {% endfor %} + requests: + {% for key, value in system_modify.resources.items() %} + {{ key }}: {{ value }} + {% endfor %} + name: {{ container.name }} + image: {{ container.image }} + {% endfor %} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/appstore/tycho/template/pod.yaml b/appstore/tycho/template/pod.yaml new file mode 100644 index 00000000..d54e8f3f --- /dev/null +++ b/appstore/tycho/template/pod.yaml @@ -0,0 +1,302 @@ +--- +# +# A Kubernetes Pod manifest template. Projects a +# Tycho system object into a YAML pod definition. +# Tags the object with a system unique +# GUID label to enable later management. +# +# Generated by Tycho {{ now() }} +# +apiVersion: v1 +kind: Pod +metadata: + name: {{ system.name }} + labels: + name: {{ system.name }} + username: {{ system.username }} + app-name: {{ system.system_name }} + original-app-name: {{ system.system_name }} + reaper-label: {{ system.system_name }} + executor: tycho + tycho-guid: {{ system.identifier }} + tycho-app-id: {{ system.app_id }} +spec: +{% if system.serviceaccount %} + serviceAccountName: {{system.serviceaccount}} +{% endif %} +{% for container in system.containers %} + {% if container.limits or container.requests %} + {% if container.limits.gpus != None and loop.first %} + tolerations: + - key: "{{ system.gpu_resource_name }}" + operator: "Exists" + effect: "NoSchedule" + {% endif %} + {% endif %} + {% if system.security_context["run_as_user"] or system.security_context.run_as_group or system.security_context.fs_group %} + securityContext: + {% if system.security_context["run_as_user"] %} + runAsUser: {{ system.security_context["run_as_user"] }} + {% endif %} + {% if system.security_context.run_as_group %} + runAsGroup: {{ system.security_context.run_as_group }} + {% endif %} + {% if system.security_context.fs_group %} + fsGroup: {{ system.security_context.fs_group }} + {% endif %} + {% endif %} +{% if (system.enable_init_container == "true") and (system.create_home_dirs == "true") and (system.dev_phase != "test") %} + initContainers: + - name: volume-tasks + image: {{ system.init_image_repository }}:{{ system.init_image_tag }} + {% if system.init_security_context.run_as_user or system.init_security_context.run_as_group %} + securityContext: + {% if system.init_security_context.run_as_user %} + runAsUser: {{ system.init_security_context.run_as_user }} + {% endif %} + {% if system.init_security_context.run_as_group %} + runAsGroup: {{ system.init_security_context.run_as_group }} + {% endif %} + {% endif %} + # Fixed resources + resources: + requests: + memory: {{ system.init_memory }} + cpu: {{ system.init_cpus }} + limits: + memory: {{ system.init_memory }} + cpu: {{ system.init_cpus }} + command: [ 'sh', '-c' ] + args: + - mkdir -p {{ system.parent_dir }}/{{ system.subpath_dir }} && + mkdir -p {{ system.parent_dir }}/{{ system.shared_dir }} && + {% if system.gitea_integration == True %} + mkdir -p {{ system.parent_dir }}/{{ system.subpath_dir }}/.ssh && + echo -e "Host {{ system.gitea_host }}\n Hostname {{ system.gitea_service_name }}\n User {{ system.gitea_user }}\n IdentityFile ~/.ssh/id_gitea" > {{ system.parent_dir }}/{{ system.subpath_dir }}/.ssh/config && + {% endif %} + ls -aln {{ system.parent_dir }} && + echo OK + volumeMounts: + - name: {{ system.stdnfs_pvc }} + mountPath: {{ system.parent_dir }} +{% endif %} +{% endfor %} + containers: +{% for container in system.containers %} + - name: {{ container.name }} + image: {{ container.image }} + {% if system.security_context.run_as_user or system.security_context.run_as_group %} + securityContext: + {% if system.security_context.run_as_user %} + runAsUser: {{ system.security_context.run_as_user }} + {% endif %} + {% if system.security_context.run_as_group %} + runAsGroup: {{ system.security_context.run_as_group }} + {% endif %} + {% endif %} +{% if container.command %} + command: {{ container.command }} +{% endif %} + env: +{% if container.env %} + {%for e in container.env %} + - name : {{ e[0] }} + value : "{{ e[1] }}" + {% endfor %} + - name : GUID + value: {{ system.identifier }} + - name: USER_NAME + value: {{ system.username }} + - name: USER + value: {{ system.username }} + {% if system.amb %} + - name: NB_PREFIX + value: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}} + - name: FB_BASEURL + value: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}} + {% else %} + - name: NB_PREFIX + value: / + - name: FB_BASEURL + value: / + {% endif %} +{% endif %} + - name: HOST + value: {{ system.host }} +{% if not container.env %} + - name : GUID + value: {{ system.identifier }} + - name: USER_NAME + value: {{ system.username }} + - name: USER + value: {{ system.username }} + {% if system.amb %} + - name: NB_PREFIX + value: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}} + - name: FB_BASEURL + value: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}} + {% else %} + - name: NB_PREFIX + value: / + - name: FB_BASEURL + value: / + {% endif %} +{% endif %} +{% if system.system_env %} + {% for env in system.system_env %} + - name: {{ env }} + value: {{ system.system_env[env]}} + {% endfor %} +{% endif %} +{% if container.expose|length > 0 %} + ports: +{% for port in container.expose %} + - containerPort: {{ container.expose[loop.index-1]['containerPort'] }} + protocol: TCP +{% endfor %} +{% endif %} # ports +{% if container.limits or container.requests %} + resources: + limits: + {% if container.limits %} + {% if container.limits.cpus != None %} + cpu: "{{ container.limits.cpus }}" + memory: "{{ container.limits.memory }}" + {% endif %} + {% if container.limits.gpus != None %} + {{ system.gpu_resource_name }}: {{ container.limits.gpus }} + {% endif %} + {% if container.limits.ephemeralStorage != None and container.limits.ephemeralStorage != "0" and container.limits.ephemeralStorage != "" %} + ephemeral-storage: {{ container.limits.ephemeralStorage }} + {% endif %} + {% endif %} + requests: + {% if container.requests %} + {% if container.requests.cpus != None %} + cpu: "{{ container.requests.cpus }}" + memory: "{{ container.requests.memory }}" + {% endif %} + {% if container.requests.gpus != None %} + {{ system.gpu_resource_name }}: {{ container.requests.gpus }} + {% endif %} + {% if container.requests.ephemeralStorage != None and container.requests.ephemeralStorage != "0" and container.requests.ephemeralStorage != "" %} + ephemeral-storage: {{ container.requests.ephemeralStorage }} + {% endif %} + {% endif %} +{% endif %} + volumeMounts: + {% if system.irods_enabled == True %} + - name: nfs + mountPath: "/home/nfs" + {% endif %} + {% if system.gitea_integration == True %} + - name: {{ system.username_all_hyphens }}-id-gitea + mountPath: {{ system.parent_dir }}/{{ system.subpath_dir }}/.ssh/id_gitea + subPath: id_gitea + readOnly: true + {% endif %} +{% if container.volumes %} +{% for volume in system.volumes %} + {% if container.name == volume['container_name'] %} + - name: {{ volume["volume_name"] }} + mountPath: {{ volume["path"] }} + subPath: {{ volume["subpath"] }} + readOnly: false + {% endif %} + {% endfor %} + {% endif %} +{% if container.liveness_probe %} + livenessProbe: + {% if container.liveness_probe.cmd %} + exec: + command: + {% for arg in container.liveness_probe.cmd %} + - {{ arg }} + {% endfor %} + {% elif container.liveness_probe.port and container.liveness_probe.path %} + httpGet: + path: {{ container.liveness_probe.path }} + port: {{ container.liveness_probe.port }} + {% if container.liveness_probe.httpHeaders %} + httpHeaders: + {% for name in container.liveness_probe.httpHeaders %} + - name: {{ name }} + value: {{ container.liveness_probe.httpHeaders[name] }} + {% endfor %} + {% endif %} + {% elif container.liveness_probe.port %} + tcpSocket: + port: {{ container.liveness_probe.port }} + {% endif %} + {% if container.liveness_probe.delay %} + initialDelaySeconds: {{ container.liveness_probe.delay }} + {% endif %} + {% if container.liveness_probe.period %} + periodSeconds: {{ container.liveness_probe.period }} + {% endif %} + {% if container.liveness_probe.threshold %} + failureThreshold: {{ container.liveness_probe.threshold }} + {% endif %} +{% endif %} +{% if container.readiness_probe %} + readinessProbe: + {% if container.readiness_probe.cmd %} + exec: + command: + {% for arg in container.readiness_probe.cmd %} + - {{ arg }} + {% endfor %} + {% elif container.readiness_probe.port and container.readiness_probe.path %} + httpGet: + path: {{ container.readiness_probe.path }} + port: {{ container.readiness_probe.port }} + {% if container.readiness_probe.httpHeaders %} + httpHeaders: + {% for name in container.readiness_probe.httpHeaders %} + - name: {{ name }} + value: {{ container.readiness_probe.httpHeaders[name] }} + {% endfor %} + {% endif %} + {% elif container.readiness_probe.port %} + tcpSocket: + port: {{ container.readiness_probe.port }} + {% endif %} + {% if container.readiness_probe.delay %} + initialDelaySeconds: {{ container.readiness_probe.delay }} + {% endif %} + {% if container.readiness_probe.period %} + periodSeconds: {{ container.readiness_probe.period }} + {% endif %} + {% if container.readiness_probe.threshold %} + failureThreshold: {{ container.readiness_probe.threshold }} + {% endif %} +{% endif %} +{% endfor %} + volumes: + {% if system.irods_enabled == True %} + - name: nfs + nfs: + server: {{ system.nfsrods_host }} + path: / + {% endif %} + {% if system.gitea_integration == True %} + - name: {{ system.username_all_hyphens }}-id-gitea + secret: + secretName: {{ system.username_all_hyphens }}-id-gitea + defaultMode: 0600 + {% endif %} +# Changes +{% for container in system.containers %} +{% if container.volumes %} +{% for volume in system.volumes %} + {% if container.name == volume['container_name']%} + {% if volume["pvc_name"] != None %} + - name: {{ volume["volume_name"] }} + persistentVolumeClaim: + claimName: {{ volume["pvc_name"] }} + {% endif %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + diff --git a/appstore/tycho/template/policy/tycho-default-netpolicy.yaml b/appstore/tycho/template/policy/tycho-default-netpolicy.yaml new file mode 100644 index 00000000..cae85338 --- /dev/null +++ b/appstore/tycho/template/policy/tycho-default-netpolicy.yaml @@ -0,0 +1,33 @@ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ system.identifier }}-netpolicy + labels: + executor: tycho + tycho-guid: {{ system.identifier }} +spec: + podSelector: + matchLabels: + tycho-guid: {{ system.identifier }} + policyTypes: + - Ingress + - Egress + ingress: + {% if system.services|length > 0 %} + - from: + {% for name, service in system.services.items () %} + {% for ip_block in service.clients %} + - ipBlock: + cidr: {{ ip_block }} + {% endfor %} + {% endfor %} + - podSelector: + matchLabels: + tycho-guid: {{ system.identifier }} + ports: + {% for name, service in system.services.items () %} + - protocol: TCP + port: {{ service.port }} + {% endfor %} + {% endif %} + diff --git a/appstore/tycho/template/pv.yaml b/appstore/tycho/template/pv.yaml new file mode 100644 index 00000000..beb76c0c --- /dev/null +++ b/appstore/tycho/template/pv.yaml @@ -0,0 +1,27 @@ +{% for volume in system.volumes %} +{% if volume["requires_nfs"] == "no" %} +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ volume["volume_name"] }} + labels: + executor: tycho + username: {{ system.username }} + tycho-guid: {{ system.identifier }} +spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + capacity: + storage: 2Gi + persistentVolumeReclaimPolicy: Recycle +{% if volume["host_path"] %} + hostPath: + path: {{ volume["host_path"] }} +{% else %} + gcePersistentDisk: + pdName: {{ volume["disk_name"] }} + {% endif %} +{% endif %} +{% endfor %} diff --git a/appstore/tycho/template/pvc.yaml b/appstore/tycho/template/pvc.yaml new file mode 100644 index 00000000..0decbd14 --- /dev/null +++ b/appstore/tycho/template/pvc.yaml @@ -0,0 +1,23 @@ +{% for volume in system.volumes %} +{% if volume["requires_nfs"] == "no" %} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + name: {{ system.name }} + username: {{ system.username }} + executor: tycho + tycho-guid: {{ system.identifier }} + name: {{ volume["claim_name"] }} +spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + volumeName: {{ volume['volume_name'] }} +status: {} +{% endif %} +{% endfor %} diff --git a/appstore/tycho/template/service.yaml b/appstore/tycho/template/service.yaml new file mode 100644 index 00000000..a41aaacc --- /dev/null +++ b/appstore/tycho/template/service.yaml @@ -0,0 +1,72 @@ +# Generated by Tycho {{ now() }} +apiVersion: v1 +kind: Service +metadata: + labels: + name: {{ service.name }} + username: {{ system.username }} + executor: tycho + tycho-app: {{ system.name }} + tycho-guid: {{ system.identifier }} + conn_string: {{ system.conn_string }} + ownerReferences: + - apiVersion: apps/v1 + controller: true + kind: Deployment + name: {{ create_deployment_api_response.metadata.name }} + uid: {{ create_deployment_api_response.metadata.uid }} + name: {{ service.name }} + {% if system.amb %} + annotations: + getambassador.io/config: | + --- + apiVersion: ambassador/v1 + kind: Mapping + name: {{system.name}}-mapping + {% if system.ambassador_id|length > 0 %} + ambassador_id: {{ system.ambassador_id }} + {% endif %} + prefix: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}}/{{system.conn_string}} + service: {{system.name}}:{{system.system_port}} + {% if system.dev_phase != 'dev' %} + headers: + REMOTE_USER: {{system.username}} + {% endif %} + {% if system.proxy_rewrite.enabled == True %} + {% if system.proxy_rewrite.target == None %} + rewrite: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}}/{{system.conn_string}} + {% else %} + rewrite: {{ system.proxy_rewrite.target }} + add_response_headers: + X-Original-Path: /private/{{system.system_name}}/{{system.username}}/{{system.identifier}}/{{system.conn_string}} + {% endif %} + {% endif %} + retry_policy: + retry_on: gateway-error + num_retries: 10 + bypass_auth: true + timeout_ms: 300000 + idle_timeout_ms: 500000 + connect_timeout_ms: 500000 + use_websocket: true + {% endif %} +resourceversion: v1 +spec: + {% if system.amb %} + type: ClusterIP + {% else %} + type: LoadBalancer + {% endif %} + selector: + name: {{ system.name }} + ports: + {% for container in system.containers %} + {% if container.name == service.name_noid %} + {% for port in container.ports %} + - name: port-{{ loop.index }} + port: {{ container.ports[loop.index-1]['containerPort'] }} + protocol: TCP + targetPort: {{ container.ports[loop.index-1]['containerPort'] }} + {% endfor %} + {% endif %} + {% endfor %}