diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..c9e9ef86cda243c0d8f946f45a693e6937893039 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,77 @@ +stages: + - build image + - test image + - build chart + - deploy +# - registry_cleanup +image: docker:19.03.1 +variables: + DOCKER_TLS_CERTDIR: "" + DOCKER_HOST: "tcp://localhost:2375" +# DOCKER_TLS_CERTDIR: "/certs" +# DOCKER_HOST: "tcp://localhost:2376" + DOCKER_DRIVER: overlay2 + HELM_EXPERIMENTAL_OCI: "1" +services: + - docker:19.03.1-dind + +include: + - project: 'cspp_geo/geosphere/geosphere-deploy' + file: '/helpers/docker_base.yaml' + - project: 'cspp_geo/geosphere/geosphere-deploy' + file: '/helpers/build_image.yaml' + +build_image_tile_gen: + extends: .build_image + variables: + IMAGE_NAME: "tile-gen" + IMAGE_DIR: "tile_gen" + +build_image_mapserver: + extends: .build_image + variables: + IMAGE_NAME: "geosphere-mapserver" + IMAGE_DIR: "mapserver" + +build_chart: + stage: build chart + tags: + - docker + - kubernetes + before_script: + - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY} + - alias helm='docker run -t --rm -e HELM_EXPERIMENTAL_OCI="$HELM_EXPERIMENTAL_OCI" -v $(pwd):/apps -w /apps -v ~/.kube:/root/.kube -v ~/.helm:/root/.helm -v ~/.config/helm:/root/.config/helm -v ~/.cache/helm:/root/.cache/helm alpine/helm:3.2.3' + - helm registry login -u ${CI_REGISTRY_USER} -p ${CI_JOB_TOKEN} ${CI_REGISTRY} + script: + - image_url="${CI_REGISTRY_IMAGE}/charts/geosphere-mapserver" + - if [ -z "$CI_COMMIT_TAG" ]; then + docker_tag=$CI_COMMIT_SHORT_SHA; + else + docker_tag=$CI_COMMIT_TAG; + fi; + - chart_tag=$docker_tag + - cd chart + - |- + sed -i "s/^appVersion: .*\$/appVersion: ${docker_tag}/g" geosphere-mapserver/Chart.yaml + - helm lint geosphere-mapserver + - helm chart save geosphere-mapserver ${image_url}:${chart_tag} + - helm chart push ${image_url}:${chart_tag} + artifacts: + paths: + - chart/geosphere-mapserver + when: on_success + expire_in: 6 hours + +#deploy_application: +# stage: deploy +# trigger: +# project: cspp_geo/geosphere/geosphere-deploy +# strategy: depend + + +#registry_cleanup: +# stage: registry_cleanup +# tags: +# - docker +# script: +# - ci/registry_cleanup.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..956ac8bdab3f33ae9be974b63b609bbd68f5456e --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# GeoSphere - MapServer (WMS) + +This repository holds the configuration files necessary to build a docker +image and helm chart for running a MapServer server in a containerized +environment. The important parts of the repository are discussed below. + +* GitLab Project: https://gitlab.ssec.wisc.edu/cspp_geo/geosphere/geosphere-mapserver +* Image Registry: https://gitlab.ssec.wisc.edu/cspp_geo/geosphere/geosphere-mapserver/container_registry +* Chart Registry: https://gitlab.ssec.wisc.edu/cspp_geo/geosphere/geosphere-mapserver/container_registry +* Issue Tracker: https://gitlab.ssec.wisc.edu/cspp_geo/geosphere/geosphere-mapserver/-/issues + +* `chart`: Configuration and definition of a helm chart that combines the + other parts of this repository into a Kubernetes installable helm chart. + See `chart/README.md` for more information. +* `tile_gen`: Docker configuration for the tile generation sidecar image. See + the `README.md` file inside for more information. +* `mapserver`: Docker configuration for the main MapServer image. See + the `README.md` file inside for more information. +* `.gitlab-ci.yml`: Continuous Integration configuration to build and test the + docker images in this repository and build the helm chart. Images and charts + are uploaded to the registries (see links above). This configuration also + triggers deployment of the application by starting the CI processing in the + [geosphere-deploy](https://gitlab.ssec.wisc.edu/cspp_geo/geosphere/geosphere-deploy/) + repository. See that repository for more information about the operation + and test deployment of the GeoSphere application. diff --git a/chart/geosphere-mapserver/.helmignore b/chart/geosphere-mapserver/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..50af0317254197a5a019f4ac2f8ecc223f93f5a7 --- /dev/null +++ b/chart/geosphere-mapserver/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/chart/geosphere-mapserver/Chart.yaml b/chart/geosphere-mapserver/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..78b39484cf46b1a84dade8bf18545228eaf905bb --- /dev/null +++ b/chart/geosphere-mapserver/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: geosphere-mapserver +description: A Helm chart for GeoSphere's MapServer +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.16.0 diff --git a/chart/geosphere-mapserver/templates/NOTES.txt b/chart/geosphere-mapserver/templates/NOTES.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd7894f320f0fb23f43544e2b193681334f310f0 --- /dev/null +++ b/chart/geosphere-mapserver/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "geosphere-mapserver.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "geosphere-mapserver.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "geosphere-mapserver.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "geosphere-mapserver.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/chart/geosphere-mapserver/templates/_helpers.tpl b/chart/geosphere-mapserver/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..7d37d154320b7b097233901c3136313561d08e24 --- /dev/null +++ b/chart/geosphere-mapserver/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "geosphere-mapserver.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "geosphere-mapserver.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "geosphere-mapserver.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "geosphere-mapserver.labels" -}} +helm.sh/chart: {{ include "geosphere-mapserver.chart" . }} +{{ include "geosphere-mapserver.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "geosphere-mapserver.selectorLabels" -}} +app.kubernetes.io/name: {{ include "geosphere-mapserver.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "geosphere-mapserver.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "geosphere-mapserver.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/chart/geosphere-mapserver/templates/deployment.yaml b/chart/geosphere-mapserver/templates/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8af420bcf1aac185f287b57e6f8ea2340f53de14 --- /dev/null +++ b/chart/geosphere-mapserver/templates/deployment.yaml @@ -0,0 +1,132 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "geosphere-mapserver.fullname" . }} + labels: + {{- include "geosphere-mapserver.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "geosphere-mapserver.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "geosphere-mapserver.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + volumes: + {{- if .Values.source.existingClaim }} + - name: src + persistentVolumeClaim: + claimName: "{{ .Values.source.existingClaim }}" + {{- else }} + # TODO: For testing only (should require s3 source) + - name: src + emptyDir: {} + {{- end }} + # put shapefiles in memory storage (small) + - name: dst + emptyDir: + medium: Memory + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: WMS_PRODUCTS + value: "{{ join " " .Values.products }}" + - name: WMS_PLATFORMS + value: "{{ join " " .Values.platforms }}" + - name: WMS_SECTORS + value: "{{ join " " .Values.sectors }}" + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + - name: {{ (printf "%s%s" .Chart.Name "-tile-gen") }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.tileGen.repository }}:{{ .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.tileGen.pullPolicy }} + env: + - name: G2G_PRODUCTS + value: "{{ join " " .Values.products }}" + - name: TILE_ARGS + value: "{{ .Values.tileArgs }}" + {{- with .Values.rabbitIn }} + {{- if .host }} + - name: RABBITMQ_HOST + value: "{{ .host }}" + - name: RABBITMQ_EXCHANGE_NAME + value: "{{ .exchange }}" + - name: RABBITMQ_USERNAME + value: "{{ .username }}" + {{- if .passwordSecret }} + - name: RABBITMQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .passwordSecret }} + key: rabbitmq-password + {{- else }} + - name: RABBITMQ_PASSWORD + value: {{ .password }} + {{- end }} + - name: AMQPFIND_TOPIC + value: "{{ .topic }}" + - name: AMQPFIND_ARGS + value: "{{ .amqpFindArgs }}" + {{- end }} + {{- end }} + {{- with .Values.rabbitOut }} + {{- if .host }} + - name: RABBITMQ_OUT_HOST + value: "{{ .host }}" + - name: RABBITMQ_OUT_EXCHANGE_NAME + value: "{{ .exchange }}" + - name: RABBITMQ_OUT_USERNAME + value: "{{ .username }}" + {{- if .passwordSecret }} + - name: RABBITMQ_OUT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .passwordSecret }} + key: rabbitmq-password + {{- else }} + - name: RABBITMQ_OUT_PASSWORD + value: {{ .password }} + {{- end }} + - name: AMQPSEND_ARGS + value: "{{ .amqpSendArgs }}" + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/chart/geosphere-mapserver/templates/ingress.yaml b/chart/geosphere-mapserver/templates/ingress.yaml new file mode 100644 index 0000000000000000000000000000000000000000..491ff46a5907d24ad8f54b3a1642af234538f3d6 --- /dev/null +++ b/chart/geosphere-mapserver/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "geosphere-mapserver.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "geosphere-mapserver.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/chart/geosphere-mapserver/templates/service.yaml b/chart/geosphere-mapserver/templates/service.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d56c718f74d9a30ca5ecc0e3fa1b93c453676a04 --- /dev/null +++ b/chart/geosphere-mapserver/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "geosphere-mapserver.fullname" . }} + labels: + {{- include "geosphere-mapserver.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "geosphere-mapserver.selectorLabels" . | nindent 4 }} diff --git a/chart/geosphere-mapserver/templates/tests/test-connection.yaml b/chart/geosphere-mapserver/templates/tests/test-connection.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2d0337da1e36af58d087028f21c63ed098353651 --- /dev/null +++ b/chart/geosphere-mapserver/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "geosphere-mapserver.fullname" . }}-test-connection" + labels: +{{ include "geosphere-mapserver.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "geosphere-mapserver.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/chart/geosphere-mapserver/values.yaml b/chart/geosphere-mapserver/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e462ac6d889965371a07a400737eb4d78ebd4e30 --- /dev/null +++ b/chart/geosphere-mapserver/values.yaml @@ -0,0 +1,109 @@ +# Default values for geosphere-mapserver. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: gitlab.ssec.wisc.edu:5555/cspp_geo/geosphere/geosphere-mapserver/geosphere-mapserver + pullPolicy: IfNotPresent +tileGen: + repository: gitlab.ssec.wisc.edu:5555/cspp_geo/geosphere/geosphere-mapserver/tile-gen + pullPolicy: IfNotPresent + +products: + - C01 + - C02 + - C03 + - C04 + - C05 + - C06 + - C07 + - C08 + - C09 + - C10 + - C11 + - C12 + - C13 + - C14 + - C15 + - C16 + - true_color_night +platforms: + - "g16" +sectors: + - "radf" + - "radc" + - "radm1" + - "radm2" + +source: + # not implemented: + s3Endpoint: "" + existingClaim: "" +rabbitIn: + host: "" + exchange: "satellite" + username: guest + password: guest + passwordSecret: "" + topic: "data.goes.*.abi.*.l1b.geotiff.all.complete" + amqpFindArgs: "" +rabbitOut: + host: "" + exchange: "satellite" + username: guest + password: guest + passwordSecret: "" + amqpSendArgs: "" +tileArgs: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/tile_gen/generate_tiles.py b/tile_gen/generate_tiles.py index 65079a9bfe1dbd0b6a578795d7e8d3ef05d72a01..7fff66d53689331f51eeb7c21ce8659a693f1ccf 100644 --- a/tile_gen/generate_tiles.py +++ b/tile_gen/generate_tiles.py @@ -84,6 +84,9 @@ def main(): help="Assume that all input geotiffs have the same " "bounding box so no need to compute it for every " "input.") + parser.add_argument('--link-or-copy', action='store_true', + help="Copy (or hardlink if possible) geotiff files to " + "be next to the created shapefiles.") parser.add_argument('out_dir', help="Output path to save tile information to (ex. '/data/tiles/{product}')") parser.add_argument('input_files', nargs="+", @@ -104,9 +107,11 @@ def main(): if args.remap: # remap if needed prod_files = list(remap_tifs(prod_files, out_dir, args.remap_suffix)) - else: + elif args.link_or_copy: # hardlink if needed prod_files = list(link_or_copy(prod_files, out_dir)) + else: + out_dir = os.path.dirname(prod_files[0]) # get all products in the current directory ext = os.path.splitext(prod_files[-1])[-1] diff --git a/tile_gen/run.sh b/tile_gen/run.sh index d4c82c222e62628d814d4145a5f01254d711b239..9b8d4a3285af552a8136b05bed36b744eac92e51 100755 --- a/tile_gen/run.sh +++ b/tile_gen/run.sh @@ -15,8 +15,19 @@ # Verify that the data mount is available test -d "/data" -export AMQPFIND_ARGS=${AMQPFIND_ARGS:-"-H cspp-geo-rabbit -X satellite -u guest -p guest"} -export AMQPSEND_ARGS=${AMQPSEND_ARGS:-"-D 15 -H cspp-geo-rabbit -X satellite -u guest -p guest"} +export RABBITMQ_HOST=${RABBITMQ_HOST:-""} +export RABBITMQ_EXCHANGE_NAME=${RABBITMQ_EXCHANGE_NAME:-"satellite"} +export RABBITMQ_USERNAME=${RABBITMQ_USERNAME:-"guest"} +export RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD:-"guest"} +export RABBITMQ_OUT_HOST=${RABBITMQ_OUT_HOST:-${RABBITMQ_HOST}} +export RABBITMQ_OUT_EXCHANGE_NAME=${RABBITMQ_OUT_EXCHANGE_NAME:-${RABBITMQ_EXCHANGE_NAME}} +export RABBITMQ_OUT_USERNAME=${RABBITMQ_OUT_USERNAME:-${RABBITMQ_USERNAME}} +export RABBITMQ_OUT_PASSWORD=${RABBITMQ_OUT_PASSWORD:-${RABBITMQ_PASSWORD}} +export AMQPFIND_ARGS=${AMQPFIND_ARGS:-""} +export AMQPSEND_ARGS=${AMQPSEND_ARGS:-"-D 15"} +# append provided args +export AMQPFIND_ARGS="-H ${RABBITMQ_HOST} -X ${RABBITMQ_EXCHANGE_NAME} -u ${RABBITMQ_USERNAME} -p ${RABBITMQ_PASSWORD} ${AMQPSEND_ARGS}" +export AMQPSEND_ARGS="-H ${RABBITMQ_OUT_HOST} -X ${RABBITMQ_OUT_EXCHANGE_NAME} -u ${RABBITMQ_OUT_USERNAME} -p ${RABBITMQ_OUT_PASSWORD} ${AMQPSEND_ARGS}" export AMQPFIND_TOPIC=${AMQPFIND_TOPIC:-'data.goes.*.abi.*.l1b.geotiff.all.complete'} export G2G_PRODUCTS=${G2G_PRODUCTS:-"C01 C02 C03 C04 C05 C06 C07 C08 C09 C10 C11 C12 C13 C14 C15 C16 true_color"} export TILE_ARGS=${TILE_ARGS:-""}