[goma] Add goma_gcp_deployer recipe

This change adds goma_gcp_deployer recipe to fuchsia.

Bug: 35512
Change-Id: I2d5569158d0d3bb024127b593e82da5d3b14d249
diff --git a/recipes/goma_gcp_deployer.expected/default service account.json b/recipes/goma_gcp_deployer.expected/default service account.json
new file mode 100644
index 0000000..09e2971
--- /dev/null
+++ b/recipes/goma_gcp_deployer.expected/default service account.json
@@ -0,0 +1,519 @@
+[
+  {
+    "cmd": [],
+    "name": "ensure gcloud"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/gcloud",
+      "-ensure-file",
+      "infra/gcloud/${platform} version:266.0.0.chromium0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:266.0.0.\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/gcloud/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.remove gcloud wrapper",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gcloud]/resources/gcloud",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.copy patched gcloud",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "config",
+      "set",
+      "project",
+      "goma-fuchsia"
+    ],
+    "name": "set gcloud project"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/config"
+    ],
+    "infra_step": true,
+    "name": "makedirs"
+  },
+  {
+    "cmd": [
+      "git",
+      "init"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git init"
+  },
+  {
+    "cmd": [
+      "git",
+      "remote",
+      "add",
+      "origin",
+      "https://fuchsia.googlesource.com/infra/config"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git remote"
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "--tags",
+      "origin",
+      "master"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git fetch"
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git checkout"
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git clean"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-global-addr",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/global-addr.yaml"
+    ],
+    "name": "deploy-global-addr"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-storage",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "deploy-storage"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev",
+      "--config",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "deploy-cluster"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "compute",
+      "addresses",
+      "describe",
+      "rbe-dev-endpoints-address",
+      "--global",
+      "--format=get(address)"
+    ],
+    "name": "get addr"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/config/goma/endpoints/api_config.yaml.in",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "read input template [START_DIR]/config/goma/endpoints/api_config.yaml.in",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml.in@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@title: Goma gRPC API on $CLUSTER@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@     Goma gRPC API on $CLUSTER in $PROJECT_ID project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@  target: \"$ADDR\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml.in@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "\ntype: google.api.Service\nconfig_version: 3\nname: rbe-dev.endpoints.goma-fuchsia.cloud.goog\ntitle: Goma gRPC API on rbe-dev\napis:\n- name: devtools_goma.ExecService\n- name: devtools_goma.FileService\n- name: devtools_goma.LogService\ndocumentation:\n   summary: >-\n     Goma gRPC API on rbe-dev in goma-fuchsia project.\nendpoints:\n- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog\n  target: \"test\"\n",
+      "[CLEANUP]/api_config.yaml"
+    ],
+    "infra_step": true,
+    "name": "write yaml [CLEANUP]/api_config.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@title: Goma gRPC API on rbe-dev@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@     Goma gRPC API on rbe-dev in goma-fuchsia project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@  target: \"test\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "pull",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "pull docker image gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+  },
+  {
+    "cmd": [
+      "docker",
+      "create",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "docker create"
+  },
+  {
+    "cmd": [],
+    "name": "copy file from container "
+  },
+  {
+    "cmd": [
+      "docker",
+      "cp",
+      ":/opt/goma/etc/service_descriptor.pb",
+      "[CLEANUP]/"
+    ],
+    "name": "copy file from container .copy /opt/goma/etc/service_descriptor.pb",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "rm",
+      "-fv",
+      ""
+    ],
+    "name": "remove  container"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "endpoints",
+      "services",
+      "deploy",
+      "[CLEANUP]/api_config.yaml",
+      "[CLEANUP]/service_descriptor.pb"
+    ],
+    "name": "gcloud endpoints"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke/rbe-dev/cluster.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"zone\": \"us-central1-a\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "container",
+      "clusters",
+      "get-credentials",
+      "--project=goma-fuchsia",
+      "--zone=us-central1-a",
+      "rbe-dev"
+    ],
+    "name": "get credential for goma-fuchsia"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"region\": \"us-central\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure kubectl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/kubectl",
+      "-ensure-file",
+      "fuchsia/third_party/kubectl/linux-amd64 version:1.16.1-00",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure kubectl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:1.16.1-0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"fuchsia/third_party/kubectl/linux-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "get",
+      "secret",
+      "nginx-ssl"
+    ],
+    "name": "kubectl get ngnix secret"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/backend-config"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-backend-config"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/goma"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-goma"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/ingress"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-ingress"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "auth-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload auth-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "exec-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload exec-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "execlog-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload execlog-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "file-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload file-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "frontend"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload frontend"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/goma_gcp_deployer.expected/default.json b/recipes/goma_gcp_deployer.expected/default.json
new file mode 100644
index 0000000..09e2971
--- /dev/null
+++ b/recipes/goma_gcp_deployer.expected/default.json
@@ -0,0 +1,519 @@
+[
+  {
+    "cmd": [],
+    "name": "ensure gcloud"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/gcloud",
+      "-ensure-file",
+      "infra/gcloud/${platform} version:266.0.0.chromium0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:266.0.0.\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/gcloud/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.remove gcloud wrapper",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gcloud]/resources/gcloud",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.copy patched gcloud",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "config",
+      "set",
+      "project",
+      "goma-fuchsia"
+    ],
+    "name": "set gcloud project"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/config"
+    ],
+    "infra_step": true,
+    "name": "makedirs"
+  },
+  {
+    "cmd": [
+      "git",
+      "init"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git init"
+  },
+  {
+    "cmd": [
+      "git",
+      "remote",
+      "add",
+      "origin",
+      "https://fuchsia.googlesource.com/infra/config"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git remote"
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "--tags",
+      "origin",
+      "master"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git fetch"
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git checkout"
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git clean"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-global-addr",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/global-addr.yaml"
+    ],
+    "name": "deploy-global-addr"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-storage",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "deploy-storage"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev",
+      "--config",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "deploy-cluster"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "compute",
+      "addresses",
+      "describe",
+      "rbe-dev-endpoints-address",
+      "--global",
+      "--format=get(address)"
+    ],
+    "name": "get addr"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/config/goma/endpoints/api_config.yaml.in",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "read input template [START_DIR]/config/goma/endpoints/api_config.yaml.in",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml.in@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@title: Goma gRPC API on $CLUSTER@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@     Goma gRPC API on $CLUSTER in $PROJECT_ID project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@  target: \"$ADDR\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml.in@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "\ntype: google.api.Service\nconfig_version: 3\nname: rbe-dev.endpoints.goma-fuchsia.cloud.goog\ntitle: Goma gRPC API on rbe-dev\napis:\n- name: devtools_goma.ExecService\n- name: devtools_goma.FileService\n- name: devtools_goma.LogService\ndocumentation:\n   summary: >-\n     Goma gRPC API on rbe-dev in goma-fuchsia project.\nendpoints:\n- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog\n  target: \"test\"\n",
+      "[CLEANUP]/api_config.yaml"
+    ],
+    "infra_step": true,
+    "name": "write yaml [CLEANUP]/api_config.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@title: Goma gRPC API on rbe-dev@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@     Goma gRPC API on rbe-dev in goma-fuchsia project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@  target: \"test\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "pull",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "pull docker image gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+  },
+  {
+    "cmd": [
+      "docker",
+      "create",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "docker create"
+  },
+  {
+    "cmd": [],
+    "name": "copy file from container "
+  },
+  {
+    "cmd": [
+      "docker",
+      "cp",
+      ":/opt/goma/etc/service_descriptor.pb",
+      "[CLEANUP]/"
+    ],
+    "name": "copy file from container .copy /opt/goma/etc/service_descriptor.pb",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "rm",
+      "-fv",
+      ""
+    ],
+    "name": "remove  container"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "endpoints",
+      "services",
+      "deploy",
+      "[CLEANUP]/api_config.yaml",
+      "[CLEANUP]/service_descriptor.pb"
+    ],
+    "name": "gcloud endpoints"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke/rbe-dev/cluster.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"zone\": \"us-central1-a\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "container",
+      "clusters",
+      "get-credentials",
+      "--project=goma-fuchsia",
+      "--zone=us-central1-a",
+      "rbe-dev"
+    ],
+    "name": "get credential for goma-fuchsia"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"region\": \"us-central\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure kubectl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/kubectl",
+      "-ensure-file",
+      "fuchsia/third_party/kubectl/linux-amd64 version:1.16.1-00",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure kubectl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:1.16.1-0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"fuchsia/third_party/kubectl/linux-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "get",
+      "secret",
+      "nginx-ssl"
+    ],
+    "name": "kubectl get ngnix secret"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/backend-config"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-backend-config"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/goma"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-goma"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/ingress"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-ingress"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "auth-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload auth-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "exec-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload exec-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "execlog-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload execlog-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "file-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload file-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "frontend"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload frontend"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/goma_gcp_deployer.expected/deploy ssl.json b/recipes/goma_gcp_deployer.expected/deploy ssl.json
new file mode 100644
index 0000000..a01fdba
--- /dev/null
+++ b/recipes/goma_gcp_deployer.expected/deploy ssl.json
@@ -0,0 +1,604 @@
+[
+  {
+    "cmd": [],
+    "name": "ensure gcloud"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/gcloud",
+      "-ensure-file",
+      "infra/gcloud/${platform} version:266.0.0.chromium0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:266.0.0.\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/gcloud/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.remove gcloud wrapper",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gcloud]/resources/gcloud",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.copy patched gcloud",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "config",
+      "set",
+      "project",
+      "goma-fuchsia"
+    ],
+    "name": "set gcloud project"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/config"
+    ],
+    "infra_step": true,
+    "name": "makedirs"
+  },
+  {
+    "cmd": [
+      "git",
+      "init"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git init"
+  },
+  {
+    "cmd": [
+      "git",
+      "remote",
+      "add",
+      "origin",
+      "https://fuchsia.googlesource.com/infra/config"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git remote"
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "--tags",
+      "origin",
+      "master"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git fetch"
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git checkout"
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git clean"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-global-addr",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/global-addr.yaml"
+    ],
+    "name": "deploy-global-addr"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-storage",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "deploy-storage"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev",
+      "--config",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "deploy-cluster"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "compute",
+      "addresses",
+      "describe",
+      "rbe-dev-endpoints-address",
+      "--global",
+      "--format=get(address)"
+    ],
+    "name": "get addr"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/config/goma/endpoints/api_config.yaml.in",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "read input template [START_DIR]/config/goma/endpoints/api_config.yaml.in",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml.in@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@title: Goma gRPC API on $CLUSTER@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@     Goma gRPC API on $CLUSTER in $PROJECT_ID project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@  target: \"$ADDR\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml.in@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "\ntype: google.api.Service\nconfig_version: 3\nname: rbe-dev.endpoints.goma-fuchsia.cloud.goog\ntitle: Goma gRPC API on rbe-dev\napis:\n- name: devtools_goma.ExecService\n- name: devtools_goma.FileService\n- name: devtools_goma.LogService\ndocumentation:\n   summary: >-\n     Goma gRPC API on rbe-dev in goma-fuchsia project.\nendpoints:\n- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog\n  target: \"test\"\n",
+      "[CLEANUP]/api_config.yaml"
+    ],
+    "infra_step": true,
+    "name": "write yaml [CLEANUP]/api_config.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@title: Goma gRPC API on rbe-dev@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@     Goma gRPC API on rbe-dev in goma-fuchsia project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@  target: \"test\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "pull",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "pull docker image gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+  },
+  {
+    "cmd": [
+      "docker",
+      "create",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "docker create"
+  },
+  {
+    "cmd": [],
+    "name": "copy file from container "
+  },
+  {
+    "cmd": [
+      "docker",
+      "cp",
+      ":/opt/goma/etc/service_descriptor.pb",
+      "[CLEANUP]/"
+    ],
+    "name": "copy file from container .copy /opt/goma/etc/service_descriptor.pb",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "rm",
+      "-fv",
+      ""
+    ],
+    "name": "remove  container"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "endpoints",
+      "services",
+      "deploy",
+      "[CLEANUP]/api_config.yaml",
+      "[CLEANUP]/service_descriptor.pb"
+    ],
+    "name": "gcloud endpoints"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke/rbe-dev/cluster.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"zone\": \"us-central1-a\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "container",
+      "clusters",
+      "get-credentials",
+      "--project=goma-fuchsia",
+      "--zone=us-central1-a",
+      "rbe-dev"
+    ],
+    "name": "get credential for goma-fuchsia"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"region\": \"us-central\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure kubectl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/kubectl",
+      "-ensure-file",
+      "fuchsia/third_party/kubectl/linux-amd64 version:1.16.1-00",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure kubectl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:1.16.1-0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"fuchsia/third_party/kubectl/linux-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "get",
+      "secret",
+      "nginx-ssl"
+    ],
+    "name": "kubectl get ngnix secret"
+  },
+  {
+    "cmd": [],
+    "name": "ensure gomatools"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[CLEANUP]/goma",
+      "-ensure-file",
+      "fuchsia_internal/third_party/goma/server/gomatools/linux-amd64 git_revision:22684ee9174606073a2604e1d58fbf03ba3ad564",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "name": "ensure gomatools.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-git_revision:226\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"fuchsia_internal/third_party/goma/server/gomatools/linux-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[CLEANUP]/goma/tlscert",
+      "-ip",
+      "rbe-dev.endpoints.goma-fuchsia.cloud.goog"
+    ],
+    "cwd": "[CLEANUP]/goma",
+    "name": "gen nginx certs"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "move",
+      "[CLEANUP]/goma/key.pem",
+      "[CLEANUP]/goma/nginx.key"
+    ],
+    "infra_step": true,
+    "name": "rename key.pem"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "move",
+      "[CLEANUP]/goma/cert.pem",
+      "[CLEANUP]/goma/nginx.crt"
+    ],
+    "infra_step": true,
+    "name": "rename cert.pem"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "create",
+      "secret",
+      "generic",
+      "nginx-ssl",
+      "--from-file=[CLEANUP]/goma/nginx.crt",
+      "--from-file=[CLEANUP]/goma/nginx.key"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "kubectl create"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/backend-config"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-backend-config"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/goma"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-goma"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/ingress"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-ingress"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "auth-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload auth-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "exec-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload exec-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "execlog-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload execlog-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "file-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload file-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "frontend"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload frontend"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/goma_gcp_deployer.expected/force update.json b/recipes/goma_gcp_deployer.expected/force update.json
new file mode 100644
index 0000000..09e2971
--- /dev/null
+++ b/recipes/goma_gcp_deployer.expected/force update.json
@@ -0,0 +1,519 @@
+[
+  {
+    "cmd": [],
+    "name": "ensure gcloud"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/gcloud",
+      "-ensure-file",
+      "infra/gcloud/${platform} version:266.0.0.chromium0",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:266.0.0.\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"infra/gcloud/resolved-platform\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "remove",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.remove gcloud wrapper",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "RECIPE_MODULE[fuchsia::gcloud]/resources/gcloud",
+      "[START_DIR]/cipd/gcloud/bin/gcloud"
+    ],
+    "infra_step": true,
+    "name": "ensure gcloud.copy patched gcloud",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "config",
+      "set",
+      "project",
+      "goma-fuchsia"
+    ],
+    "name": "set gcloud project"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "ensure-directory",
+      "--mode",
+      "0777",
+      "[START_DIR]/config"
+    ],
+    "infra_step": true,
+    "name": "makedirs"
+  },
+  {
+    "cmd": [
+      "git",
+      "init"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git init"
+  },
+  {
+    "cmd": [
+      "git",
+      "remote",
+      "add",
+      "origin",
+      "https://fuchsia.googlesource.com/infra/config"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git remote"
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "--tags",
+      "origin",
+      "master"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git fetch"
+  },
+  {
+    "cmd": [
+      "git",
+      "checkout",
+      "-f",
+      "FETCH_HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git checkout"
+  },
+  {
+    "cmd": [
+      "git",
+      "rev-parse",
+      "HEAD"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git rev-parse"
+  },
+  {
+    "cmd": [
+      "git",
+      "clean",
+      "-f",
+      "-d",
+      "-x"
+    ],
+    "cwd": "[START_DIR]/config",
+    "name": "git clean"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-global-addr",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/global-addr.yaml"
+    ],
+    "name": "deploy-global-addr"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev-storage",
+      "--config",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "deploy-storage"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "deployment-manager",
+      "deployments",
+      "create",
+      "rbe-dev",
+      "--config",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "deploy-cluster"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "compute",
+      "addresses",
+      "describe",
+      "rbe-dev-endpoints-address",
+      "--global",
+      "--format=get(address)"
+    ],
+    "name": "get addr"
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/config/goma/endpoints/api_config.yaml.in",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "name": "read input template [START_DIR]/config/goma/endpoints/api_config.yaml.in",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml.in@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@title: Goma gRPC API on $CLUSTER@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@     Goma gRPC API on $CLUSTER in $PROJECT_ID project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@- name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml.in@  target: \"$ADDR\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml.in@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "\ntype: google.api.Service\nconfig_version: 3\nname: rbe-dev.endpoints.goma-fuchsia.cloud.goog\ntitle: Goma gRPC API on rbe-dev\napis:\n- name: devtools_goma.ExecService\n- name: devtools_goma.FileService\n- name: devtools_goma.LogService\ndocumentation:\n   summary: >-\n     Goma gRPC API on rbe-dev in goma-fuchsia project.\nendpoints:\n- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog\n  target: \"test\"\n",
+      "[CLEANUP]/api_config.yaml"
+    ],
+    "infra_step": true,
+    "name": "write yaml [CLEANUP]/api_config.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@api_config.yaml@@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@type: google.api.Service@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@config_version: 3@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@title: Goma gRPC API on rbe-dev@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@apis:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.ExecService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.FileService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: devtools_goma.LogService@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@documentation:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@   summary: >-@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@     Goma gRPC API on rbe-dev in goma-fuchsia project.@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@endpoints:@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@- name: rbe-dev.endpoints.goma-fuchsia.cloud.goog@@@",
+      "@@@STEP_LOG_LINE@api_config.yaml@  target: \"test\"@@@",
+      "@@@STEP_LOG_END@api_config.yaml@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "pull",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "pull docker image gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+  },
+  {
+    "cmd": [
+      "docker",
+      "create",
+      "gcr.io/fuchsia-toolchain-images-gcr/frontend:latest"
+    ],
+    "name": "docker create"
+  },
+  {
+    "cmd": [],
+    "name": "copy file from container "
+  },
+  {
+    "cmd": [
+      "docker",
+      "cp",
+      ":/opt/goma/etc/service_descriptor.pb",
+      "[CLEANUP]/"
+    ],
+    "name": "copy file from container .copy /opt/goma/etc/service_descriptor.pb",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "docker",
+      "rm",
+      "-fv",
+      ""
+    ],
+    "name": "remove  container"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "endpoints",
+      "services",
+      "deploy",
+      "[CLEANUP]/api_config.yaml",
+      "[CLEANUP]/service_descriptor.pb"
+    ],
+    "name": "gcloud endpoints"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke/rbe-dev/cluster.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke/rbe-dev/cluster.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"zone\": \"us-central1-a\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/gcloud/bin/gcloud",
+      "container",
+      "clusters",
+      "get-credentials",
+      "--project=goma-fuchsia",
+      "--zone=us-central1-a",
+      "rbe-dev"
+    ],
+    "name": "get credential for goma-fuchsia"
+  },
+  {
+    "cmd": [
+      "python",
+      "-u",
+      "RECIPE_MODULE[fuchsia::yaml]/resources/parse_yaml.py",
+      "[START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml"
+    ],
+    "name": "load yaml [START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"region\": \"us-central\"@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "ensure kubectl"
+  },
+  {
+    "cmd": [
+      "cipd",
+      "ensure",
+      "-root",
+      "[START_DIR]/cipd/kubectl",
+      "-ensure-file",
+      "fuchsia/third_party/kubectl/linux-amd64 version:1.16.1-00",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "infra_step": true,
+    "name": "ensure kubectl.ensure_installed",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"\": [@@@",
+      "@@@STEP_LOG_LINE@json.output@      {@@@",
+      "@@@STEP_LOG_LINE@json.output@        \"instance_id\": \"resolved-instance_id-of-version:1.16.1-0\", @@@",
+      "@@@STEP_LOG_LINE@json.output@        \"package\": \"fuchsia/third_party/kubectl/linux-amd64\"@@@",
+      "@@@STEP_LOG_LINE@json.output@      }@@@",
+      "@@@STEP_LOG_LINE@json.output@    ]@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "get",
+      "secret",
+      "nginx-ssl"
+    ],
+    "name": "kubectl get ngnix secret"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/backend-config"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-backend-config"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/goma"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-goma"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "apply",
+      "-f",
+      "[START_DIR]/config/goma/k8s/rbe-dev/ingress"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "deploy-ingress"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "auth-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload auth-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "exec-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload exec-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "execlog-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload execlog-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "file-server"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload file-server"
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd/kubectl/kubectl",
+      "rollout",
+      "restart",
+      "deployment",
+      "frontend"
+    ],
+    "env": {
+      "CLOUDSDK_COMPUTE_REGION": "us-central",
+      "CLOUDSDK_COMPUTE_ZONE": "us-central1-a",
+      "CLOUDSDK_CONTAINER_CLUSTER": "rbe-dev"
+    },
+    "name": "reload frontend"
+  },
+  {
+    "name": "$result"
+  }
+]
\ No newline at end of file
diff --git a/recipes/goma_gcp_deployer.py b/recipes/goma_gcp_deployer.py
new file mode 100644
index 0000000..82ce4d0
--- /dev/null
+++ b/recipes/goma_gcp_deployer.py
@@ -0,0 +1,359 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Recipe for deploying goma configurations."""
+
+from recipe_engine.recipe_api import Property
+from string import Template
+
+DEPS = [
+    'fuchsia/docker',
+    'fuchsia/gcloud',
+    'fuchsia/git',
+    'fuchsia/goma',
+    'fuchsia/gsutil',
+    'fuchsia/kubectl',
+    'fuchsia/yaml',
+    'recipe_engine/archive',
+    'recipe_engine/buildbucket',
+    'recipe_engine/cipd',
+    'recipe_engine/context',
+    'recipe_engine/file',
+    'recipe_engine/json',
+    'recipe_engine/path',
+    'recipe_engine/properties',
+    'recipe_engine/raw_io',
+    'recipe_engine/step',
+    'recipe_engine/time',
+    'recipe_engine/url',
+]
+
+PROPERTIES = {
+    'repository':
+        Property(
+            kind=str,
+            help='repository that hold the goma configurations',
+            default='https://fuchsia.googlesource.com/infra/config'),
+    'config_root':
+        Property(
+            kind=str,
+            help='root directory in repository that stores goma configurations',
+            default='goma'),
+    'domain':
+        Property(kind=str, help='domain', default='gcr.io'),
+    'project':
+        Property(
+            kind=str,
+            help='gcloud project that hosting goma clusters',
+            default='goma-fuchsia'),
+    'cluster':
+        Property(kind=str, help='the name of the cluster', default='rbe-dev'),
+    'toolchain_project':
+        Property(
+            kind=str,
+            help='gcloud project that hosting goma clusters',
+            default='fuchsia-toolchain-images-gcr'),
+    'gke_operation':
+        Property(
+            kind=str,
+            help='operation argument for gcloud deployment manager, can be \'create\' or \'update\'. Leave it blank means skip gke related steps',
+            default=''),
+    'deploy_endpoint':
+        Property(
+            kind=bool, help='deploy endpoint configuration.', default=False),
+    'reload_services':
+        Property(
+            kind=bool, help='deploy endpoint configuration.', default=True),
+}
+
+YAML_TEMPLATE_TEST_DATA = """
+type: google.api.Service
+config_version: 3
+name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog
+title: Goma gRPC API on $CLUSTER
+apis:
+- name: devtools_goma.ExecService
+- name: devtools_goma.FileService
+- name: devtools_goma.LogService
+documentation:
+   summary: >-
+     Goma gRPC API on $CLUSTER in $PROJECT_ID project.
+endpoints:
+- name: $CLUSTER.endpoints.$PROJECT_ID.cloud.goog
+  target: "$ADDR"
+"""
+
+GOMATOOLS_VERSION = 'git_revision:22684ee9174606073a2604e1d58fbf03ba3ad564'
+
+GOMA_SERVICES = [
+    'auth-server',
+    'exec-server',
+    'execlog-server',
+    'file-server',
+    'frontend',
+]
+
+
+def get_zone_for_cluster(api, goma_config_dir, cluster):
+  cluster_yaml = goma_config_dir.join('gke', cluster, 'cluster.yaml')
+  if not api.path.exists(cluster_yaml):
+    raise api.step.StepFailure('unknown cluster name %s' %
+                               cluster)  # pragma no cover
+  return api.yaml.retrieve_field(cluster_yaml, 'zone')
+
+
+def get_region_for_cluster(api, goma_config_dir, cluster):
+  storage_yaml = goma_config_dir.join('gke-res', cluster, 'storage.yaml')
+  if not api.path.exists(storage_yaml):
+    raise api.step.StepFailure('unknown cluster name %s' %
+                               cluster)  # pragma no cover
+  return api.yaml.retrieve_field(storage_yaml, 'region')
+
+
+def generate_yaml_from_template(api,
+                                input_yaml,
+                                output_yaml,
+                                project,
+                                cluster,
+                                addr,
+                                test_data=''):
+  replace_dict = {
+      'PROJECT_ID': project,
+      'CLUSTER': cluster,
+      'ADDR': addr,
+  }
+  infile = api.file.read_text(
+      'read input template %s' % input_yaml, input_yaml, test_data=test_data)
+  outfile = ''
+  for curline in infile.splitlines(True):
+    curline_temp = Template(curline)
+    curline = curline_temp.substitute(replace_dict)
+    outfile += curline
+  api.file.write_text('write yaml %s' % output_yaml, output_yaml, outfile)
+
+
+def ensure_gomatools(api, gomatools_dir):
+  with api.step.nest('ensure gomatools'):
+    pkgs = api.cipd.EnsureFile()
+    pkgs.add_package(
+        'fuchsia_internal/third_party/goma/server/gomatools/linux-amd64',
+        GOMATOOLS_VERSION)
+    api.cipd.ensure(gomatools_dir, pkgs)
+
+
+def deploy_nginx_ssl(api, project, cluster, zone, region):
+  # Check if SSL certs already exist.
+  kube_result = api.kubectl(
+      'get',
+      'secret',
+      'nginx-ssl',
+      step_name='kubectl get ngnix secret',
+      ok_ret='any',
+  )
+  if kube_result.retcode == 0:
+    return
+  # Generate new SSL certs.
+  gomatools_dir = api.path['cleanup'].join('goma')
+  ensure_gomatools(api, gomatools_dir)
+  with api.context(cwd=gomatools_dir):
+    api.step('gen nginx certs', [
+        gomatools_dir.join('tlscert'), '-ip',
+        '{}.endpoints.{}.cloud.goog'.format(cluster, project)
+    ])
+  api.file.move('rename key.pem', gomatools_dir.join('key.pem'),
+                gomatools_dir.join('nginx.key'))
+  api.file.move('rename cert.pem', gomatools_dir.join('cert.pem'),
+                gomatools_dir.join('nginx.crt'))
+  with api.context(
+      env={
+          'CLOUDSDK_COMPUTE_REGION': region,
+          'CLOUDSDK_COMPUTE_ZONE': zone,
+          'CLOUDSDK_CONTAINER_CLUSTER': cluster,
+      }):
+    api.kubectl('create', 'secret', 'generic', 'nginx-ssl',
+                '--from-file=%s' % str(gomatools_dir.join('nginx.crt')),
+                '--from-file=%s' % str(gomatools_dir.join('nginx.key')))
+
+
+def RunSteps(api, repository, config_root, domain, project, cluster,
+             toolchain_project, gke_operation, deploy_endpoint,
+             reload_services):
+  api.gcloud(
+      'config', 'set', 'project', project, step_name='set gcloud project')
+  # checkout
+  infra_config_dir = api.path['start_dir'].join('config')
+  goma_config_dir = infra_config_dir.join(config_root)
+  api.git.checkout(
+      url=repository, path=infra_config_dir, submodules=False, cache=False)
+  # for recipe tests, add mock files.
+  api.path.mock_add_paths(
+      goma_config_dir.join('gke', 'rbe-dev', 'cluster.yaml'))
+  api.path.mock_add_paths(
+      goma_config_dir.join('gke-res', 'rbe-dev', 'storage.yaml'))
+  if gke_operation:
+    gke_res_dir = goma_config_dir.join('gke-res', cluster)
+    gke_dir = goma_config_dir.join('gke', cluster)
+    api.gcloud(
+        'deployment-manager',
+        'deployments',
+        gke_operation,
+        '%s-global-addr' % cluster,
+        '--config',
+        gke_res_dir.join('global-addr.yaml'),
+        step_name='deploy-global-addr')
+    api.gcloud(
+        'deployment-manager',
+        'deployments',
+        gke_operation,
+        '%s-storage' % cluster,
+        '--config',
+        gke_res_dir.join('storage.yaml'),
+        step_name='deploy-storage')
+    api.gcloud(
+        'deployment-manager',
+        'deployments',
+        gke_operation,
+        cluster,
+        '--config',
+        gke_dir.join('cluster.yaml'),
+        step_name='deploy-cluster')
+
+  if deploy_endpoint:
+    endpoints_dir = goma_config_dir.join('endpoints')
+    ip_name = '%s-endpoints-address' % cluster
+    addr = api.gcloud(
+        'compute',
+        'addresses',
+        'describe',
+        ip_name,
+        '--global',
+        '--format=get(address)',
+        step_name='get addr',
+        stdout=api.raw_io.output()).stdout.strip()
+    if not addr:
+      raise api.step.InfraFailure('address not found in %s' %
+                                  ip_name)  # pragma no cover
+    api_config_yaml = api.path['cleanup'].join('api_config.yaml')
+    service_pb = api.path['cleanup'].join('service_descriptor.pb')
+    generate_yaml_from_template(
+        api,
+        endpoints_dir.join('api_config.yaml.in'),
+        api_config_yaml,
+        project,
+        cluster,
+        addr,
+        test_data=YAML_TEMPLATE_TEST_DATA)
+    with api.docker.create(
+        api.url.join(domain, toolchain_project, 'frontend') + ':' +
+        'latest') as temp_copy:
+      api.docker.copy(temp_copy, ['/opt/goma/etc/service_descriptor.pb'],
+                      api.path['cleanup'])
+    api.gcloud('endpoints', 'services', 'deploy', api_config_yaml, service_pb)
+
+  zone = get_zone_for_cluster(api, goma_config_dir, cluster)
+  api.gcloud(
+      'container',
+      'clusters',
+      'get-credentials',
+      '--project=%s' % project,
+      '--zone=%s' % zone,
+      cluster,
+      step_name='get credential for %s' % project)
+  region = get_region_for_cluster(api, goma_config_dir, cluster)
+  deploy_nginx_ssl(api, project, cluster, zone, region)
+
+  with api.context(
+      env={
+          'CLOUDSDK_COMPUTE_REGION': region,
+          'CLOUDSDK_COMPUTE_ZONE': zone,
+          'CLOUDSDK_CONTAINER_CLUSTER': cluster,
+      }):
+    api.kubectl(
+        'apply',
+        '-f',
+        str(goma_config_dir.join('k8s', cluster, 'backend-config')),
+        step_name='deploy-backend-config',
+    )
+    api.kubectl(
+        'apply',
+        '-f',
+        str(goma_config_dir.join('k8s', cluster, 'goma')),
+        step_name='deploy-goma',
+    )
+    api.kubectl(
+        'apply',
+        '-f',
+        str(goma_config_dir.join('k8s', cluster, 'ingress')),
+        step_name='deploy-ingress',
+    )
+    if reload_services:
+      for service in GOMA_SERVICES:
+        api.kubectl(
+            'rollout',
+            'restart',
+            'deployment',
+            service,
+            step_name='reload %s' % service)
+
+
+def GenTests(api):
+  default_properties = api.properties(
+      repository='https://fuchsia.googlesource.com/infra/config',
+      config_root='goma',
+      domain='gcr.io',
+      project='goma-fuchsia',
+      cluster='rbe-dev',
+      gke_operation='create',
+      deploy_endpoint=True,
+      rbe_service_account='rbe-cluster',
+      force_update_secrets=False)
+
+  force_update_properties = api.properties(
+      repository='https://fuchsia.googlesource.com/infra/config',
+      config_root='goma',
+      domain='gcr.io',
+      project='goma-fuchsia',
+      cluster='rbe-dev',
+      gke_operation='create',
+      deploy_endpoint=True,
+      rbe_service_account='rbe-cluster',
+      force_update_secrets=True)
+
+  default_service_account_properties = api.properties(
+      repository='https://fuchsia.googlesource.com/infra/config',
+      config_root='goma',
+      domain='gcr.io',
+      project='goma-fuchsia',
+      cluster='rbe-dev',
+      gke_operation='create',
+      deploy_endpoint=True,
+      rbe_service_account='',
+      force_update_secrets=True)
+
+  region_step_data = api.step_data(
+      'load yaml [START_DIR]/config/goma/gke-res/rbe-dev/storage.yaml',
+      stdout=api.json.output({'region': 'us-central'}))
+  zone_step_data = api.step_data(
+      'load yaml [START_DIR]/config/goma/gke/rbe-dev/cluster.yaml',
+      stdout=api.json.output({'zone': 'us-central1-a'}))
+
+  yield api.test('default') + default_properties + api.override_step_data(
+      'get addr', api.raw_io.stream_output('test')) + api.buildbucket.try_build(
+          git_repo='https://fuchsia.googlesource.com/integration'
+      ) + region_step_data + zone_step_data
+  yield api.test(
+      'deploy ssl'
+  ) + default_properties + region_step_data + zone_step_data + api.override_step_data(
+      'get addr', api.raw_io.stream_output('test')) + api.override_step_data(
+          'kubectl get ngnix secret', retcode=1) + api.buildbucket.try_build(
+              git_repo='https://fuchsia.googlesource.com/integration')
+  yield api.test(
+      'force update'
+  ) + force_update_properties + region_step_data + zone_step_data + api.override_step_data(
+      'get addr', api.raw_io.stream_output('test')) + api.buildbucket.try_build(
+          git_repo='https://fuchsia.googlesource.com/integration')
+  yield api.test(
+      'default service account'
+  ) + default_service_account_properties + region_step_data + zone_step_data + api.override_step_data(
+      'get addr', api.raw_io.stream_output('test')) + api.buildbucket.try_build(
+          git_repo='https://fuchsia.googlesource.com/integration')