# Copyright 2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ################################################################################ """Cloud function to build base images on Google Cloud Builder.""" import datetime import logging import google.auth from googleapiclient.discovery import build BASE_IMAGES = [ 'base-image', 'base-clang', 'base-builder', 'base-runner', 'base-runner-debug', ] BASE_PROJECT = 'oss-fuzz-base' TAG_PREFIX = f'gcr.io/{BASE_PROJECT}/' BASE_SANITIZER_LIBS_IMAGE = TAG_PREFIX + 'base-sanitizer-libs-builder' MSAN_LIBS_IMAGE = TAG_PREFIX + 'msan-libs-builder' def _get_base_image_steps(images, tag_prefix=TAG_PREFIX): """Returns build steps for given images.""" steps = [{ 'args': [ 'clone', 'https://github.com/google/oss-fuzz.git', ], 'name': 'gcr.io/cloud-builders/git', }] for base_image in images: steps.append({ 'args': [ 'build', '-t', tag_prefix + base_image, '.', ], 'dir': 'oss-fuzz/infra/base-images/' + base_image, 'name': 'gcr.io/cloud-builders/docker', }) return steps def get_logs_url(build_id, project_id='oss-fuzz-base'): """Returns url that displays the build logs.""" url_format = ('https://console.developers.google.com/logs/viewer?' 'resource=build%2Fbuild_id%2F{0}&project={1}') return url_format.format(build_id, project_id) # pylint: disable=no-member def run_build(steps, images): """Execute the retrieved build steps in gcp.""" credentials, _ = google.auth.default() build_body = { 'steps': steps, 'timeout': str(6 * 3600) + 's', 'options': { 'machineType': 'N1_HIGHCPU_32' }, 'images': images } cloudbuild = build('cloudbuild', 'v1', credentials=credentials, cache_discovery=False) build_info = cloudbuild.projects().builds().create(projectId=BASE_PROJECT, body=build_body).execute() build_id = build_info['metadata']['build']['id'] logging.info('Build ID: %s', build_id) logging.info('Logs: %s', get_logs_url(build_id, BASE_PROJECT)) def base_builder(event, context): """Cloud function to build base images.""" del event, context tag_prefix = f'gcr.io/{BASE_PROJECT}/' steps = _get_base_image_steps(BASE_IMAGES, tag_prefix) images = [tag_prefix + base_image for base_image in BASE_IMAGES] run_build(steps, images) def _get_msan_steps(image): """Get build steps for msan-libs-builder.""" timestamp = datetime.datetime.utcnow().strftime('%Y%m%d%H%M') upload_name = 'msan-libs-' + timestamp + '.zip' steps = _get_base_image_steps([ 'base-sanitizer-libs-builder', 'msan-libs-builder', ]) steps.extend([{ 'name': image, 'args': [ 'bash', '-c', 'cd /msan && zip -r /workspace/libs.zip .', ], }, { 'name': 'gcr.io/cloud-builders/gsutil', 'args': [ 'cp', '/workspace/libs.zip', 'gs://oss-fuzz-msan-libs/' + upload_name, ], }]) return steps def base_msan_builder(event, context): """Cloud function to build base images.""" del event, context steps = _get_msan_steps(MSAN_LIBS_IMAGE) images = [ BASE_SANITIZER_LIBS_IMAGE, MSAN_LIBS_IMAGE, ] run_build(steps, images)