# -*- mode: Python -*- settings = read_json('tilt-settings.json', default={}) load('ext://restart_process', 'docker_build_with_restart') allow_k8s_contexts(settings.get("allowed_contexts")) default_registry(settings.get('default_registry')) IMG = 'eks-a-controller-manager' PROJECT_ROOT = os.path.abspath('./..') CONTROLLERS_FOLDER = PROJECT_ROOT + '/controllers' MANAGER_FOLDER = 'manager' MANAGER_PATH = PROJECT_ROOT + '/' + MANAGER_FOLDER DOCKERFILE_PATH = MANAGER_PATH + '/docker/linux/eks-anywhere-cluster-controller/Dockerfile' OUTPUT_DIR = 'tilt' OUTPUT_PATH = MANAGER_PATH + '/' + OUTPUT_DIR OUTPUT_BIN_FOLDER = OUTPUT_PATH + '/bin' PKG_FOLDER = PROJECT_ROOT + '/pkg' API_FOLDER = PKG_FOLDER + '/api' CONFIG_FOLDER = PROJECT_ROOT + '/config' KUSTOMIZE_TILT_FOLDER = CONFIG_FOLDER + '/tilt/' KUSTOMIZE_BIN = PROJECT_ROOT + '/hack/tools/bin/kustomize' def eksa_components(): local( KUSTOMIZE_BIN + ' edit set image controller=' + IMG, dir=KUSTOMIZE_TILT_FOLDER, ) return kustomize(KUSTOMIZE_TILT_FOLDER, kustomize_bin = KUSTOMIZE_BIN) def manager_binary_dir(os, arch): platform_subfolder = platform(os, arch) return OUTPUT_BIN_FOLDER + '/eks-anywhere-cluster-controller/' + platform_subfolder def platform(os, arch): return os + '-' + arch def manager_build_cmd(os, arch): return 'make create-cluster-controller-binaries-local GO_OS=' + os + ' GO_ARCH=' + arch + ' OUTPUT_DIR=' + OUTPUT_PATH # This retrieves the latest available tag for our minimal nonroot image # we can't use it since it doesn't have a shell and that's required to make # tilt's live_update work. We can can update this to use a different image name # if we ever get support for a shell in a minimal image def manager_base_image(): base_repo = 'public.ecr.aws/eks-distro-build-tooling' cluster_controller_base_image_name = 'eks-distro-minimal-base-nonroot' cluster_controller_base_tag = str(local('cat ' + MANAGER_FOLDER + '/EKS_DISTRO_MINIMAL_BASE_TAG_FILE', dir=PROJECT_ROOT)).rstrip('\n') return base_repo + '/' + cluster_controller_base_image_name + ':' + cluster_controller_base_tag ################# # This is where the actual configuration logic exists ################# # ignore kustomize tilt folder to avoid infinite loop watch_settings(ignore=[KUSTOMIZE_TILT_FOLDER]) # TODO: figure a way to dynamically get the k8s arch, specially for M1's cluster_os = 'linux' cluster_arch = "amd64" cluster_platform = platform(cluster_os, cluster_arch) manager_binary_dir = manager_binary_dir(cluster_os, cluster_arch) # Build the api config manifests when anything changes in the api, controllers or manager folders # This can be either go API structs, RBAC in the controllers through kubebuilder # or other kubebuilder comments in the manager main.go local_resource( "generate-eksa-components", "make generate-manifests", dir = PROJECT_ROOT, deps = [API_FOLDER, CONTROLLERS_FOLDER, MANAGER_FOLDER], ignore = [OUTPUT_DIR], ) # Build the controller manager go binary when something changes in pkg, controllers or manager # Exclude the manager binary itself to avoid a infinite loop local_resource( 'eksa-controller-manager-build', manager_build_cmd(cluster_os, cluster_arch), dir = PROJECT_ROOT, deps = [MANAGER_PATH, CONTROLLERS_FOLDER, PKG_FOLDER, "go.mod", "go.sum"], ignore = [manager_binary_dir, API_FOLDER + '/*/zz_generated.deepcopy.go', DOCKERFILE_PATH], ) # Run kustomize in the config folder for the Tilt overlay and apply yaml to cluster # This also takes care of rerunning itself if anything changes # kustomize watches the target folders and re runs if anything changes # Kustomize returns a Blob, which is watched by k8s_yaml, and when the blob changes, # the yaml is reapplied to the cluster k8s_yaml(eksa_components()) manager_binary_path = manager_binary_dir + "/manager" # It's important to use a folder where the nonroot user can write, # since Tilt needs to write to that folder in order to replace the binary (live_update) manager_binary_dir_in_container = '/home/nonroot' manager_binary_path_in_container = manager_binary_dir_in_container + '/manager' # Build image for controller manager, trigger when the manager binary changes # This uses live_update, so it won't rebuild the whole container image every time # the binary changes, just at the begginning # When the binary changes, it updates the running container live, by replacing the binary # and restarting the process. This is way faster than building a new image and pushing and pulling docker_build_with_restart( IMG, # This is the docker build context path: use the project root so we have access to all folders PROJECT_ROOT, dockerfile=DOCKERFILE_PATH, build_args = { # TODO: we should eventually move this to one of our own minimal images # once we have one with sh support 'BASE_IMAGE': 'gcr.io/distroless/base:debug', 'TARGETARCH': cluster_arch, 'TARGETOS': cluster_os, # All paths inside a dockerfile need to be relative to the context path 'MANAGER_BIN_PATH': os.path.relpath(manager_binary_path, basepath = PROJECT_ROOT), 'DST_MANAGER_BINARY_DIR': manager_binary_dir_in_container, }, entrypoint=[manager_binary_path_in_container, '--feature-gates'], # `only` is a mix between the context passed to the docker build and the paths that will # trigger a new build. This means we need to include all paths needed in the dockerfile # but nothing else, so we don't trigger image builds unnecessary only=[manager_binary_path, '_output', 'ATTRIBUTION.txt'], trigger=[manager_binary_path], live_update=[ sync(manager_binary_path, manager_binary_path_in_container), ] )