generate/repo.py (119 lines of code) (raw):
# Copyright 2024 Google LLC
#
# 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.
import os
import copy
import shutil
import util
CONFIG_FILE = os.environ.get("EZTF_INPUT_CONFIG")
CONFIG_BUCKET = os.environ.get("EZTF_CONFIG_BUCKET")
OUTPUT_BUCKET = os.environ.get("EZTF_OUTPUT_BUCKET")
LOCAL_OUTPUT_DIR = os.environ.get("EZTF_OUTPUT_DIR") or "../ezytf-gen-data/eztf-output"
SSM_HOST = os.environ.get("EZTF_SSM_HOST")
EZTF_MODE = os.environ.get("EZTF_MODE")
CDKTF_OUTPUT_DIR = os.environ.get("EZTF_CDK_OUTPUT_DIR") or "cdktf.out"
REPO_TEMPLATE_FILE = [
"../templates/tf_repo/setup_project.sh",
"../templates/tf_repo/README.md",
]
EX_VAR_ENV = {
"setup_project_id",
"setup_service_account_name",
"gcs_bucket",
"gcs_bucket_location",
"organization_id",
"setup_service_account",
}
def code_push_remote(repo_name, repo_folder, git_uri):
"""pushed to remote repository/bucket"""
if OUTPUT_BUCKET:
gcs_prefix = f"eztf-output/{repo_name}/{repo_name}-{util.time_str()}"
util.upload_folder_to_gcs(OUTPUT_BUCKET, repo_folder, gcs_prefix)
if SSM_HOST and not git_uri:
git_uri = util.ssm_repository(repo_name, SSM_HOST)
if git_uri:
util.push_folder_to_git(repo_folder, git_uri, "auto")
def tf_creator(repo_folder, clean_org, tfstacks, stacks_variable):
"splits tf file"
for config_sub_stack in tfstacks:
stack_name = f"gcp-{clean_org}-{config_sub_stack}"
cdktf_out_file = util.cdktf_output(
stack_name=stack_name, output_folder=CDKTF_OUTPUT_DIR
)
repo_subfolder_path = f"{repo_folder}/{config_sub_stack}"
util.split_tf_file(cdktf_out_file, repo_subfolder_path)
if stacks_variable.get(config_sub_stack):
util.tf_vars_file(stacks_variable[config_sub_stack], repo_subfolder_path)
def yaml_json_creator(repo_folder, resource, data):
"json yaml file creator"
for my_item in data:
item = copy.deepcopy(my_item)
filename = my_item.get("eztf_filename", util.random_str(n=5))
del item["eztf_filename"]
if not filename.endswith(f".{resource}"):
filename += f".{resource}"
if resource == "yaml":
util.write_file_yaml(f"{repo_folder}/{filename}", item)
elif resource == "json":
util.write_file_json(f"{repo_folder}/{filename}", item)
def anyfile_creator(repo_folder, resource, data):
"any file creator"
for item in data:
filename = item.get("eztf_filename", util.random_str(n=5))
util.write_file_any(f"{repo_folder}/{filename}", item.get("content", ""))
creator_function = {
"yaml": yaml_json_creator,
"json": yaml_json_creator,
"anyfile": anyfile_creator,
}
def my_creator(repo_folder, config):
"other supported file creator"
for config_sub_stack, range_resource in config["eztf"]["stacks"].items():
repo_subfolder_path = f"{repo_folder}/{config_sub_stack}"
for rr in range_resource:
for range, resource in rr.items():
if creator_function.get(resource):
creator_function[resource](
repo_subfolder_path, resource, config.get(range)
)
def add_setup_scripts(repo_folder, tf_vars):
"add scripts file and env var in repo folder"
script_var = {}
for var in EX_VAR_ENV.intersection(tf_vars):
script_var[var] = tf_vars[var]
if not script_var.get("setup_service_account"):
sa_name = script_var.get("setup_service_account_name", "")
sa_proj = script_var.get("setup_project_id", "")
script_var["setup_service_account"] = (
f"{sa_name}@{sa_proj}.iam.gserviceaccount.com"
)
if script_var.get("setup_service_account"):
script_var["GOOGLE_IMPERSONATE_SERVICE_ACCOUNT"] = script_var[
"setup_service_account"
]
if script_var.get("setup_project_id"):
script_var["USER_PROJECT_OVERRIDE"] = "true"
script_var["GOOGLE_BILLING_PROJECT"] = script_var["setup_project_id"]
env_str = "\n".join(
[f"export {name}={value}" for name, value in script_var.items()]
)
with open(f"{repo_folder}/script_env", "w", encoding="utf-8") as script_env:
script_env.write(env_str)
for template_file in REPO_TEMPLATE_FILE:
dest_file = os.path.join(repo_folder, os.path.basename(template_file))
shutil.copy2(template_file, dest_file)
if __name__ == "__main__":
config_dict = util.get_file_yaml(CONFIG_FILE)
variable = config_dict["variable"]
domain = variable["domain"]
config_type = variable.get("eztf_config_name") or "ezytf"
tfstacks = config_dict["eztf"].get("tf_stacks", [])
stack_variables = config_dict["eztf"].get("tf_vars", {})
config_git_uri = variable.get("output_git_uri", "")
clean_domain = util.clean_res_id(domain)
repo = f"gcp-{clean_domain}-{config_type}"
output_folder = f"{LOCAL_OUTPUT_DIR}/{repo}"
tf_creator(output_folder, clean_domain, tfstacks, stack_variables)
my_creator(output_folder, config_dict)
add_setup_scripts(output_folder, variable)
code_push_remote(repo, output_folder, config_git_uri)
if EZTF_MODE == "service":
print(f"cleaning up {output_folder} and {CDKTF_OUTPUT_DIR}")
shutil.rmtree(output_folder)
shutil.rmtree(CDKTF_OUTPUT_DIR)