blob: 196519c60936a2cbe35babffc790f10c75809106 [file] [log] [blame]
# 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/kubectl",
"fuchsia/status_check",
"fuchsia/yaml",
"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/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_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):
# 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"),
)
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)
region = get_region_for_cluster(api, goma_config_dir, cluster)
api.gcloud(
"container",
"clusters",
"get-credentials",
"--project=%s" % project,
"--region=%s" % region,
cluster,
step_name="get credential for %s" % project,
)
with api.context(
env={"CLOUDSDK_COMPUTE_REGION": region, "CLOUDSDK_CONTAINER_CLUSTER": cluster,}
):
api.kubectl(
"apply",
"-f",
str(goma_config_dir.join("k8s", cluster, "goma")),
step_name="deploy-goma",
)
api.kubectl(
"annotate",
"serviceaccount",
"--overwrite",
"default",
"iam.gke.io/gcp-service-account=rbe-cluster@%s.iam.gserviceaccount.com"
% project,
step_name="annotate default ksa",
)
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, "ingress")),
step_name="deploy-ingress",
)
deploy_nginx_ssl(api, project, cluster)
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"}),
)
yield api.status_check.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
yield api.status_check.test(
"deploy_ssl"
) + default_properties + region_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.status_check.test(
"force_update"
) + force_update_properties + region_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.status_check.test(
"default_service_account"
) + default_service_account_properties + region_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"
)