diff --git a/.gitignore b/.gitignore index a96217845..7472860ee 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,11 @@ terraform/aws/kconfigs/Kconfig.instance.generated terraform/aws/kconfigs/Kconfig.location.generated terraform/aws/scripts/__pycache__/ +terraform/oci/kconfigs/Kconfig.image.generated +terraform/oci/kconfigs/Kconfig.location.generated +terraform/oci/kconfigs/Kconfig.shape.generated +terraform/oci/scripts/__pycache__/ + .cloud.initialized scripts/__pycache__/ diff --git a/scripts/dynamic-cloud-kconfig.Makefile b/scripts/dynamic-cloud-kconfig.Makefile index d3225076f..d5015f5f2 100644 --- a/scripts/dynamic-cloud-kconfig.Makefile +++ b/scripts/dynamic-cloud-kconfig.Makefile @@ -20,8 +20,16 @@ AWS_KCONFIG_LOCATION := $(AWS_KCONFIG_DIR)/Kconfig.location.generated AWS_KCONFIGS := $(AWS_KCONFIG_AMI) $(AWS_KCONFIG_INSTANCE) $(AWS_KCONFIG_LOCATION) +# OCI dynamic configuration +OCI_KCONFIG_DIR := terraform/oci/kconfigs +OCI_KCONFIG_IMAGE := $(OCI_KCONFIG_DIR)/Kconfig.image.generated +OCI_KCONFIG_LOCATION := $(OCI_KCONFIG_DIR)/Kconfig.location.generated +OCI_KCONFIG_SHAPE := $(OCI_KCONFIG_DIR)/Kconfig.shape.generated + +OCI_KCONFIGS := $(OCI_KCONFIG_IMAGE) $(OCI_KCONFIG_LOCATION) $(OCI_KCONFIG_SHAPE) + # Add generated files to mrproper clean list -KDEVOPS_MRPROPER += $(LAMBDALABS_KCONFIGS) $(AWS_KCONFIGS) +KDEVOPS_MRPROPER += $(LAMBDALABS_KCONFIGS) $(AWS_KCONFIGS) $(OCI_KCONFIGS) # Touch Lambda Labs generated files so Kconfig can source them # This ensures the files exist (even if empty) before Kconfig runs @@ -32,7 +40,11 @@ dynamic_lambdalabs_kconfig_touch: dynamic_aws_kconfig_touch: $(Q)touch $(AWS_KCONFIGS) -DYNAMIC_KCONFIG += dynamic_lambdalabs_kconfig_touch dynamic_aws_kconfig_touch +# Touch OCI generated files so Kconfig can source them +dynamic_oci_kconfig_touch: + $(Q)touch $(OCI_KCONFIGS) + +DYNAMIC_KCONFIG += dynamic_lambdalabs_kconfig_touch dynamic_aws_kconfig_touch dynamic_oci_kconfig_touch # Lambda Labs targets use --provider argument for efficiency cloud-config-lambdalabs: @@ -42,6 +54,10 @@ cloud-config-lambdalabs: cloud-config-aws: $(Q)python3 scripts/generate_cloud_configs.py --provider aws +# OCI targets use --provider argument for efficiency +cloud-config-oci: + $(Q)python3 scripts/generate_cloud_configs.py --provider oci + # Clean Lambda Labs generated files clean-cloud-config-lambdalabs: $(Q)rm -f $(LAMBDALABS_KCONFIGS) @@ -50,7 +66,11 @@ clean-cloud-config-lambdalabs: clean-cloud-config-aws: $(Q)rm -f $(AWS_KCONFIGS) -DYNAMIC_CLOUD_KCONFIG += cloud-config-lambdalabs cloud-config-aws +# Clean OCI generated files +clean-cloud-config-oci: + $(Q)rm -f $(OCI_KCONFIGS) + +DYNAMIC_CLOUD_KCONFIG += cloud-config-lambdalabs cloud-config-aws cloud-config-oci cloud-config-help: @echo "Cloud-specific dynamic kconfig targets:" @@ -72,4 +92,7 @@ cloud-list-all: $(Q)chmod +x scripts/cloud_list_all.sh $(Q)scripts/cloud_list_all.sh -PHONY += cloud-config cloud-config-lambdalabs cloud-config-aws clean-cloud-config clean-cloud-config-lambdalabs clean-cloud-config-aws cloud-config-help cloud-list-all +PHONY += cloud-config clean-cloud-config cloud-config-help cloud-list-all +PHONY += cloud-config-aws clean-cloud-config-aws +PHONY += cloud-config-lambdalabs clean-cloud-config-lambdalabs +PHONY += cloud-config-oci clean-cloud-config-oci diff --git a/scripts/generate_cloud_configs.py b/scripts/generate_cloud_configs.py index 8c039f534..d14b56d20 100755 --- a/scripts/generate_cloud_configs.py +++ b/scripts/generate_cloud_configs.py @@ -147,6 +147,52 @@ def generate_aws_kconfig() -> bool: return all_success +def generate_oci_kconfig() -> bool: + """ + Generate OCI Kconfig files. + Returns True on success, False on failure. + """ + script_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(script_dir) + oci_scripts_dir = os.path.join(project_root, "terraform", "oci", "scripts") + oci_kconfigs_dir = os.path.join(project_root, "terraform", "oci", "kconfigs") + + # Define the script-to-output mapping + scripts_to_run = [ + ("gen_kconfig_image", "Kconfig.image.generated"), + ("gen_kconfig_location", "Kconfig.location.generated"), + ("gen_kconfig_shape", "Kconfig.shape.generated"), + ] + + all_success = True + + for script_name, kconfig_file in scripts_to_run: + script_path = os.path.join(oci_scripts_dir, script_name) + output_path = os.path.join(oci_kconfigs_dir, kconfig_file) + + # Run the script and capture its output + result = subprocess.run( + [script_path], + capture_output=True, + text=True, + check=False, + ) + + if result.returncode == 0: + # Write the output to the corresponding Kconfig file + try: + with open(output_path, "w") as f: + f.write(result.stdout) + except IOError as e: + print(f"Error writing {kconfig_file}: {e}", file=sys.stderr) + all_success = False + else: + print(f"Error running {script_name}: {result.stderr}", file=sys.stderr) + all_success = False + + return all_success + + def process_lambdalabs(): """Process Lambda Labs configuration.""" # Generate Kconfig files first @@ -186,8 +232,13 @@ def process_gce(): def process_oci(): - """Process OCI configuration (placeholder).""" - print("⚠ OCI: Dynamic configuration not yet implemented") + """Process OCI configuration.""" + kconfig_generated = generate_oci_kconfig() + if kconfig_generated: + print("✓ OCI: Kconfig files generated successfully") + else: + print("⚠ OCI: Failed to generate Kconfig files - using defaults") + print() def main(): diff --git a/terraform/oci/Kconfig b/terraform/oci/Kconfig index 566442868..3369578b3 100644 --- a/terraform/oci/Kconfig +++ b/terraform/oci/Kconfig @@ -1,10 +1,19 @@ +# OCI provider configuration +# +# This file sources dynamically Kconfig menus. Run +# 'make cloud-config-oci' to populate the .generated files +# with current OCI resource information. + if TERRAFORM_OCI menu "Resource location" -source "terraform/oci/kconfigs/Kconfig.location" +source "terraform/oci/kconfigs/Kconfig.location.generated" endmenu menu "Compute" -source "terraform/oci/kconfigs/Kconfig.compute" +comment "Shape selection" +source "terraform/oci/kconfigs/Kconfig.shape.generated" +comment "OS image selection" +source "terraform/oci/kconfigs/Kconfig.image.generated" endmenu menu "Storage" source "terraform/oci/kconfigs/Kconfig.storage" diff --git a/terraform/oci/kconfigs/Kconfig.compute b/terraform/oci/kconfigs/Kconfig.compute deleted file mode 100644 index c847726a5..000000000 --- a/terraform/oci/kconfigs/Kconfig.compute +++ /dev/null @@ -1,79 +0,0 @@ -choice - prompt "OCI shape family" - default TERRAFORM_OCI_SHAPE_FAMILY_FLEX - help - This option selects the class of virtual hardware (CPUs and - memory) to provision for each target node. Most CPU - architectures, including x86, run two threads per physical - core, so one OCPU is the equal of two vCPUs for x86-based - compute. - - Which shapes are available is limited by your subscription - and what hardware has been deployed in your selected region. - -config TERRAFORM_OCI_SHAPE_FAMILY_FLEX - bool "Flex shapes" - help - A flexible shape is a virtual machine that lets you - customize the number of OCPUs and the amount of memory - per instance. The network bandwidth and number of VNICs - scale proportionately with the number of OCPUs. - -config TERRAFORM_OCI_SHAPE_FAMILY_GENERIC - bool "Generic shapes" - help - These shapes are recommended for developers who do not - require a specific model of CPU for their workflows. - -config TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL - bool "Bare metal" - help - A bare metal shape is a whole physical machine without - virtualization. This gives deterministic performance - characteristics but is less configurable than a flex - shape. - -endchoice - -source "terraform/oci/kconfigs/shapes/Kconfig.flex" -source "terraform/oci/kconfigs/shapes/Kconfig.generic" -source "terraform/oci/kconfigs/shapes/Kconfig.bm" - -choice - prompt "Distribution" - default TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX - help - Select the Linux distribution to install on each instance. - -config TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX - bool "Oracle Linux" - help - Select this if you want to use a release of Oracle Linux - as the operating system in your instances. - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU - bool "Ubuntu" - help - Select this if you want to use a release of Ubuntu Linux - as the operating system in your instances. - -config TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM - bool "Custom image OCID" - help - Select this if you want to enter a specific OCID for - an OS image. Use this if you wish to use a custom or - marketplace image not included in the fixed choices in - this menu. - - The image you specify must reside in the same region as - your instances. - - More image choices are available: - - https://docs.oracle.com/en-us/iaas/images/ - -endchoice - -source "terraform/oci/kconfigs/images/Kconfig.OracleLinux" -source "terraform/oci/kconfigs/images/Kconfig.Ubuntu" -source "terraform/oci/kconfigs/images/Kconfig.custom" diff --git a/terraform/oci/kconfigs/images/Kconfig.OracleLinux b/terraform/oci/kconfigs/Kconfig.image similarity index 62% rename from terraform/oci/kconfigs/images/Kconfig.OracleLinux rename to terraform/oci/kconfigs/Kconfig.image index 9c48be5b9..5bce58255 100644 --- a/terraform/oci/kconfigs/images/Kconfig.OracleLinux +++ b/terraform/oci/kconfigs/Kconfig.image @@ -1,3 +1,38 @@ +choice + prompt "Distribution" + default TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX + help + Select the Linux distribution to install on each instance. + +config TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX + bool "Oracle Linux" + help + Select this if you want to use a release of Oracle Linux + as the operating system in your instances. + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU + bool "Ubuntu" + help + Select this if you want to use a release of Ubuntu Linux + as the operating system in your instances. + +config TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM + bool "Custom image OCID" + help + Select this if you want to enter a specific OCID for + an OS image. Use this if you wish to use a custom or + marketplace image not included in the fixed choices in + this menu. + + The image you specify must reside in the same region as + your instances. + + More image choices are available: + + https://docs.oracle.com/en-us/iaas/images/ + +endchoice + if TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX choice @@ -28,6 +63,7 @@ config TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX_7_9_GPU config TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX_7_9_ARM64 bool "Oracle Linux 7.9 (aarch64)" + depends on TARGET_ARCH_ARM64 help (extended support) Oracle-Linux-7.9-aarch64-2024.11.30-0 @@ -310,3 +346,187 @@ config TERRAFORM_OCI_OS_IMAGE_OCID endif # TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX_9_6_X86 endif # TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU + +choice + prompt "OS release" + default TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 if TARGET_ARCH_ARM64 + default TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 if TARGET_ARCH_X86_64 + help + Select the release of Ubuntu to install on each instance. + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 + bool "Ubuntu 20.04 (aarch64)" + depends on TARGET_ARCH_ARM64 + help + Canonical-Ubuntu-20.04-aarch64-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2004/canonical-ubuntu-20-04-aarch64-2025-01-31-1.htm + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 + bool "Ubuntu 20.04 (x86)" + depends on TARGET_ARCH_X86_64 + help + Canonical-Ubuntu-20.04-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2004/canonical-ubuntu-20-04-2025-01-31-1.htm + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 + bool "Ubuntu 22.04 (aarch64)" + depends on TARGET_ARCH_ARM64 + help + Canonical-Ubuntu-22.04-aarch64-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2204/canonical-ubuntu-22-04-aarch64-2025-01-31-1.htm + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 + bool "Ubuntu 22.04 (x86)" + depends on TARGET_ARCH_X86_64 + help + Canonical-Ubuntu-22.04-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2204/canonical-ubuntu-22-04-2025-01-31-1.htm + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 + bool "Ubuntu 24.04 (aarch64)" + depends on TARGET_ARCH_ARM64 + help + Canonical-Ubuntu-24.04-aarch64-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2404/canonical-ubuntu-24-04-aarch64-2025-01-31-1.htm + +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 + bool "Ubuntu 24.04 (x86)" + depends on TARGET_ARCH_X86_64 + help + Canonical-Ubuntu-24.04-2025.01.31-1 + + Image release notes: + https://docs.oracle.com/en-us/iaas/images/ubuntu-2404/canonical-ubuntu-24-04-2025-01-31-1.htm + +endchoice + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaawnlatjgnpqmaercoleknle5nml47l23iwnxi7ba4xup5ajyarv6q" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaawkgecsy7fbxqeus5zpw5n7ykyeugzizcehrildz7pzavfjrcsswa" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaaesuvbpyo4lpim5xxx3lwj4lcppfkzp6tsape336epukyndi2pora" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaoox5ewo5bq67sr2spakzdiw4rrxjlgbr25ucqwglb4aonastyhzq" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaan5qjp6hcvi2ry24zp233wlotljj4llfghqbyn2yoon6wnc3se6pa" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaa7habuxhtxdty52x47eq27lq7gjweoun4urafpv2s6ysggbp6nrxa" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaaji2v46qtemmx7bpuoomw2uvrsatvgxrlnp3orvdptbl6ppbal67q" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaa2dt3oqmhwwd3z2o3wynfltfa3rms6pc2uhvr2kmjmmyvqr2li7pq" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaa3uvxetf4g6beur4qn2ublcl6set7qtda2rcfcv5h7vul6aut2q7q" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaaj276t4bm4hyqyu44mjcuzndgn6lku4th3nfaglwpiyzsp6lozqlq" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaaagkdbfci5rxx5yikkifi7culqosi7r623osdzqv25rkanxd66dbq" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaafbbzzsemfbol5vvyevlmqxhcv6avfo5z6larkuty4safdn3epoha" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaaw65jff6tnjbr7x2c2lr3qlf46l2sthpuidxaurmar2oxjmqry3qa" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaagyn7e55mr27m7ttkp2exvdix4ugfl2jbl66xognsge44vuqat4ma" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaazjumsfmhi2tztgs7wuhesifaj2fw47xmyycltazjmr5xa6k7do7q" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaaka77df4vad27cm7oamg3zji6ir5zrvbwbkm7ks7rvucd3bwsbqnq" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaaca7s2s5pgnooszcjysi7pknrimayqjds6knvjascphe2r767m6vq" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaamvlfwzlzk6jkyuhoylf6k3n5r7tz6m2lvf5fqjdpsrdwqk2dtcqa" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaai6c6hx7wvx5l3oikjcv7am3n23etmbuu3byic3grzhx5ylthigca" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaa7fy2cysnjwlpoghk5ax65jmvyteg4bjmji6xmm4gti6xg4kmgfia" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaaq3uhgye3ryjqjcnnmtk5u4ipa5ffhxawa6nvgelzccz5x3pfel4a" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaar5u2rj2ahg2btnlmnxhzijozcuqb5lhjit327wesufuhjkytfwha" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaa7f6r242tdb2roknj3odb264g2tduvc2je2u4kbp3hqatiy4sngcq" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaax6vsn7c34viq7yfu3j3v554x6dulorapywrorheltorxoi5on4dq" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaalldybw6d43ihqwcqeeedsncrl4s7qfczeqwq2eb5cohxj2gyp72q" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaaooprivsfvvblwxhl2oww3djmz4mnjxjqczxunvahu5dvt3dwlfka" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaadstv5y7ovuhvg354zu4mocto6eyy4frnnfartpl34hmaupg6upka" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaf6wyj6ap2frgctd7xj7pkxwvj7gowxinvy6xbjzz3z4cv2d5ycfa" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaablkb5j2kdyqehb7qp2scdyuwslknidn4a53qzje2fxcbw3ji5gta" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaa3dfmmuqlupm4gruk5weh5mncxbmfzn36uoj2relmdwvud44zc3ea" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaaccxuq5zox772ncsaggg52xngwcipzfqoqwu7x73owhvd7ula7xpa" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaappswsfuaodghkbps5kjh3bhjxxpaig56wiirxhjlo5tktsuypkha" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaagkujhljfnogpc4zmmith4sbyh32ltdnxrjx7wksssyv3yv3xkasq" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaat27vwnwxtqovgbceettrrkmvlgwgyn3vj7rhyblih7omqhi4cioa" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaayojwvhljgwqgpdyqcqdjh4jgbcfd6hu2axdogi4c3si5stmdcjxa" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaj4vzogabouc3ypajurmwx53juolg745la7mmi4qj3grijoaziwlq" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaahga37ytba47p2msqzbh5erbqvniyybcvteuh646vgyw4tltustka" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaasghgl3azcm2kjya2p7urk4nnpfjlrxlfeosn5jc6hm5epn7gkrra" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaag7js2gmz5yrqtnnjirri52hyqvsymn7gp5a7gwg5jtd2jowpi7tq" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaatsp47wenhtuubuusyi2pgohpnal5fz6jyz4ur5n4juwhj2n2egpq" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 + +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml + default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaakzztav5leofa43dcc7uecenhjhazdxlaj7u3kgnfsu65fcw6c5wa" if TERRAFORM_OCI_REGION_HYD + default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaayvok7wg6qwbf2nfeohcqroie2eyplrlxsuwjut7rdugg7jftk7pa" if TERRAFORM_OCI_REGION_BOM + default "ocid1.image.oc1.ca-montreal-1.aaaaaaaa33jzjdmexcf5zaiia2mhjou5xsgatzaqm4mwgqejp2f77bnjhwpa" if TERRAFORM_OCI_REGION_YUL + default "ocid1.image.oc1.ca-toronto-1.aaaaaaaadtwzeffczkghs325xbzeocp4i7ghpeims5insf6a65kxcpmk4bwq" if TERRAFORM_OCI_REGION_YYZ + default "ocid1.image.oc1.iad.aaaaaaaaaja5re7chpwbyrdk57xya7qoxdktskrn5lph7fsuai5zccaefawa" if TERRAFORM_OCI_REGION_IAD + default "ocid1.image.oc1.us-chicago-1.aaaaaaaaslqsnubarsgmpktkbewqedpf76vp6e5k7nafoxpx3aaryag2a6ba" if TERRAFORM_OCI_REGION_ORD + default "ocid1.image.oc1.phx.aaaaaaaapplpp6okoc73a23mdag6k6mwgscofpx2p7bcigeo3ztjktsd53pa" if TERRAFORM_OCI_REGION_PHX + default "ocid1.image.oc1.us-sanjose-1.aaaaaaaaebdhewufiuvsm6kh2eccurg5zdchwfr24heayt4h4bwenee3lwka" if TERRAFORM_OCI_REGION_SJC + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU + +if TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM + +config TERRAFORM_OCI_OS_IMAGE_OCID + string "OS image OCID" + output yaml + help + An image is a template of a virtual hard drive. It + contains the operating system and other software for each + instance. Select an image by specifying the OCID of the + image to use. You can select: + + - An older release than the latest image release + - An older operating system release + - A custom-made image + + More detail is available: + + https://docs.oracle.com/en-us/iaas/Content/Compute/References/bringyourownimage.htm + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM diff --git a/terraform/oci/kconfigs/Kconfig.location b/terraform/oci/kconfigs/Kconfig.location deleted file mode 100644 index eb5bac8d9..000000000 --- a/terraform/oci/kconfigs/Kconfig.location +++ /dev/null @@ -1,58 +0,0 @@ -choice - prompt "OCI Region" - default TERRAFORM_OCI_REGION_ORD - help - A region is a collection of geographically co-located data - centers that share data and hardware resources. For more - information: - - https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm - - Using this menu, select the region in which you wish to - deploy your kdevops resources. Your tenancy must be - subscribed to the region you select here. Use: - - $ oci iam region-subscription list - - for a list of regions to which your tenancy subscribes. - -config TERRAFORM_OCI_REGION_HYD - bool "India South (Hyderabad)" - -config TERRAFORM_OCI_REGION_BOM - bool "India West (Mumbai)" - -config TERRAFORM_OCI_REGION_YUL - bool "Canada Southeast (Montreal)" - -config TERRAFORM_OCI_REGION_YYZ - bool "Canada Southeast (Toronto)" - -config TERRAFORM_OCI_REGION_IAD - bool "US East (Ashburn)" - -config TERRAFORM_OCI_REGION_ORD - bool "US Midwest (Chicago)" - -config TERRAFORM_OCI_REGION_PHX - bool "US West (Phoenix)" - -config TERRAFORM_OCI_REGION_SJC - bool "US West (San Jose)" - -endchoice - -source "terraform/oci/kconfigs/regions/Kconfig.ap-hyderabad-1" -source "terraform/oci/kconfigs/regions/Kconfig.ap-mumbai-1" -source "terraform/oci/kconfigs/regions/Kconfig.ca-montreal-1" -source "terraform/oci/kconfigs/regions/Kconfig.ca-toronto-1" -source "terraform/oci/kconfigs/regions/Kconfig.us-ashburn-1" -source "terraform/oci/kconfigs/regions/Kconfig.us-chicago-1" -source "terraform/oci/kconfigs/regions/Kconfig.us-phoenix-1" -source "terraform/oci/kconfigs/regions/Kconfig.us-sanjose-1" - -config TERRAFORM_OCI_COMPARTMENT_NAME - string "OCI compartment name" - output yaml - help - The compartment name where your instances are to be created. diff --git a/terraform/oci/kconfigs/images/Kconfig.Ubuntu b/terraform/oci/kconfigs/images/Kconfig.Ubuntu deleted file mode 100644 index 5a87cd4c3..000000000 --- a/terraform/oci/kconfigs/images/Kconfig.Ubuntu +++ /dev/null @@ -1,162 +0,0 @@ -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU - -choice - prompt "OS release" - default TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 if TARGET_ARCH_ARM64 - default TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 if TARGET_ARCH_X86_64 - help - Select the release of Ubuntu to install on each instance. - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 - bool "Ubuntu 20.04 (aarch64)" - depends on TARGET_ARCH_ARM64 - help - Canonical-Ubuntu-20.04-aarch64-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2004/canonical-ubuntu-20-04-aarch64-2025-01-31-1.htm - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 - bool "Ubuntu 20.04 (x86)" - depends on TARGET_ARCH_X86_64 - help - Canonical-Ubuntu-20.04-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2004/canonical-ubuntu-20-04-2025-01-31-1.htm - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 - bool "Ubuntu 22.04 (aarch64)" - depends on TARGET_ARCH_ARM64 - help - Canonical-Ubuntu-22.04-aarch64-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2204/canonical-ubuntu-22-04-aarch64-2025-01-31-1.htm - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 - bool "Ubuntu 22.04 (x86)" - depends on TARGET_ARCH_X86_64 - help - Canonical-Ubuntu-22.04-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2204/canonical-ubuntu-22-04-2025-01-31-1.htm - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 - bool "Ubuntu 24.04 (aarch64)" - depends on TARGET_ARCH_ARM64 - help - Canonical-Ubuntu-24.04-aarch64-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2404/canonical-ubuntu-24-04-aarch64-2025-01-31-1.htm - -config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 - bool "Ubuntu 24.04 (x86)" - depends on TARGET_ARCH_X86_64 - help - Canonical-Ubuntu-24.04-2025.01.31-1 - - Image release notes: - https://docs.oracle.com/en-us/iaas/images/ubuntu-2404/canonical-ubuntu-24-04-2025-01-31-1.htm - -endchoice - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaawnlatjgnpqmaercoleknle5nml47l23iwnxi7ba4xup5ajyarv6q" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaawkgecsy7fbxqeus5zpw5n7ykyeugzizcehrildz7pzavfjrcsswa" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaaesuvbpyo4lpim5xxx3lwj4lcppfkzp6tsape336epukyndi2pora" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaoox5ewo5bq67sr2spakzdiw4rrxjlgbr25ucqwglb4aonastyhzq" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaan5qjp6hcvi2ry24zp233wlotljj4llfghqbyn2yoon6wnc3se6pa" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaa7habuxhtxdty52x47eq27lq7gjweoun4urafpv2s6ysggbp6nrxa" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaaji2v46qtemmx7bpuoomw2uvrsatvgxrlnp3orvdptbl6ppbal67q" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaa2dt3oqmhwwd3z2o3wynfltfa3rms6pc2uhvr2kmjmmyvqr2li7pq" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_ARM64 - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaa3uvxetf4g6beur4qn2ublcl6set7qtda2rcfcv5h7vul6aut2q7q" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaaj276t4bm4hyqyu44mjcuzndgn6lku4th3nfaglwpiyzsp6lozqlq" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaaagkdbfci5rxx5yikkifi7culqosi7r623osdzqv25rkanxd66dbq" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaafbbzzsemfbol5vvyevlmqxhcv6avfo5z6larkuty4safdn3epoha" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaaw65jff6tnjbr7x2c2lr3qlf46l2sthpuidxaurmar2oxjmqry3qa" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaagyn7e55mr27m7ttkp2exvdix4ugfl2jbl66xognsge44vuqat4ma" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaazjumsfmhi2tztgs7wuhesifaj2fw47xmyycltazjmr5xa6k7do7q" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaaka77df4vad27cm7oamg3zji6ir5zrvbwbkm7ks7rvucd3bwsbqnq" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_20_04_X86 - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaaca7s2s5pgnooszcjysi7pknrimayqjds6knvjascphe2r767m6vq" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaamvlfwzlzk6jkyuhoylf6k3n5r7tz6m2lvf5fqjdpsrdwqk2dtcqa" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaai6c6hx7wvx5l3oikjcv7am3n23etmbuu3byic3grzhx5ylthigca" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaa7fy2cysnjwlpoghk5ax65jmvyteg4bjmji6xmm4gti6xg4kmgfia" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaaq3uhgye3ryjqjcnnmtk5u4ipa5ffhxawa6nvgelzccz5x3pfel4a" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaar5u2rj2ahg2btnlmnxhzijozcuqb5lhjit327wesufuhjkytfwha" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaa7f6r242tdb2roknj3odb264g2tduvc2je2u4kbp3hqatiy4sngcq" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaax6vsn7c34viq7yfu3j3v554x6dulorapywrorheltorxoi5on4dq" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_ARM64 - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaalldybw6d43ihqwcqeeedsncrl4s7qfczeqwq2eb5cohxj2gyp72q" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaaooprivsfvvblwxhl2oww3djmz4mnjxjqczxunvahu5dvt3dwlfka" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaadstv5y7ovuhvg354zu4mocto6eyy4frnnfartpl34hmaupg6upka" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaf6wyj6ap2frgctd7xj7pkxwvj7gowxinvy6xbjzz3z4cv2d5ycfa" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaablkb5j2kdyqehb7qp2scdyuwslknidn4a53qzje2fxcbw3ji5gta" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaa3dfmmuqlupm4gruk5weh5mncxbmfzn36uoj2relmdwvud44zc3ea" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaaccxuq5zox772ncsaggg52xngwcipzfqoqwu7x73owhvd7ula7xpa" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaappswsfuaodghkbps5kjh3bhjxxpaig56wiirxhjlo5tktsuypkha" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_22_04_X86 - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaagkujhljfnogpc4zmmith4sbyh32ltdnxrjx7wksssyv3yv3xkasq" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaat27vwnwxtqovgbceettrrkmvlgwgyn3vj7rhyblih7omqhi4cioa" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaayojwvhljgwqgpdyqcqdjh4jgbcfd6hu2axdogi4c3si5stmdcjxa" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaaj4vzogabouc3ypajurmwx53juolg745la7mmi4qj3grijoaziwlq" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaahga37ytba47p2msqzbh5erbqvniyybcvteuh646vgyw4tltustka" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaasghgl3azcm2kjya2p7urk4nnpfjlrxlfeosn5jc6hm5epn7gkrra" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaag7js2gmz5yrqtnnjirri52hyqvsymn7gp5a7gwg5jtd2jowpi7tq" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaatsp47wenhtuubuusyi2pgohpnal5fz6jyz4ur5n4juwhj2n2egpq" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_ARM64 - -if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 - -config TERRAFORM_OCI_OS_IMAGE_OCID - string - output yaml - default "ocid1.image.oc1.ap-hyderabad-1.aaaaaaaakzztav5leofa43dcc7uecenhjhazdxlaj7u3kgnfsu65fcw6c5wa" if TERRAFORM_OCI_REGION_HYD - default "ocid1.image.oc1.ap-mumbai-1.aaaaaaaayvok7wg6qwbf2nfeohcqroie2eyplrlxsuwjut7rdugg7jftk7pa" if TERRAFORM_OCI_REGION_BOM - default "ocid1.image.oc1.ca-montreal-1.aaaaaaaa33jzjdmexcf5zaiia2mhjou5xsgatzaqm4mwgqejp2f77bnjhwpa" if TERRAFORM_OCI_REGION_YUL - default "ocid1.image.oc1.ca-toronto-1.aaaaaaaadtwzeffczkghs325xbzeocp4i7ghpeims5insf6a65kxcpmk4bwq" if TERRAFORM_OCI_REGION_YYZ - default "ocid1.image.oc1.iad.aaaaaaaaaja5re7chpwbyrdk57xya7qoxdktskrn5lph7fsuai5zccaefawa" if TERRAFORM_OCI_REGION_IAD - default "ocid1.image.oc1.us-chicago-1.aaaaaaaaslqsnubarsgmpktkbewqedpf76vp6e5k7nafoxpx3aaryag2a6ba" if TERRAFORM_OCI_REGION_ORD - default "ocid1.image.oc1.phx.aaaaaaaapplpp6okoc73a23mdag6k6mwgscofpx2p7bcigeo3ztjktsd53pa" if TERRAFORM_OCI_REGION_PHX - default "ocid1.image.oc1.us-sanjose-1.aaaaaaaaebdhewufiuvsm6kh2eccurg5zdchwfr24heayt4h4bwenee3lwka" if TERRAFORM_OCI_REGION_SJC - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU_24_04_X86 - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU diff --git a/terraform/oci/kconfigs/images/Kconfig.custom b/terraform/oci/kconfigs/images/Kconfig.custom deleted file mode 100644 index 144b974fb..000000000 --- a/terraform/oci/kconfigs/images/Kconfig.custom +++ /dev/null @@ -1,20 +0,0 @@ -if TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM - -config TERRAFORM_OCI_OS_IMAGE_OCID - string "OS image OCID" - output yaml - help - An image is a template of a virtual hard drive. It - contains the operating system and other software for each - instance. Select an image by specifying the OCID of the - image to use. You can select: - - - An older release than the latest image release - - An older operating system release - - A custom-made image - - More detail is available: - - https://docs.oracle.com/en-us/iaas/Content/Compute/References/bringyourownimage.htm - -endif # TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM diff --git a/terraform/oci/kconfigs/regions/Kconfig.ap-hyderabad-1 b/terraform/oci/kconfigs/regions/Kconfig.ap-hyderabad-1 deleted file mode 100644 index f4ac37ef3..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.ap-hyderabad-1 +++ /dev/null @@ -1,28 +0,0 @@ -if TERRAFORM_OCI_REGION_HYD - -config TERRAFORM_OCI_REGION - string - output yaml - default "ap-hyderabad-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_HYD_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_HYD_AD1 - bool "1" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_HYD_1_AD1 - -endif # TERRAFORM_OCI_REGION_HYD_1 diff --git a/terraform/oci/kconfigs/regions/Kconfig.ap-mumbai-1 b/terraform/oci/kconfigs/regions/Kconfig.ap-mumbai-1 deleted file mode 100644 index f05b595c3..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.ap-mumbai-1 +++ /dev/null @@ -1,27 +0,0 @@ -if TERRAFORM_OCI_REGION_BOM - -config TERRAFORM_OCI_REGION - string - output yaml - default "ap-mumbai-1" -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_BOM_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_BOM_AD1 - bool "1" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_BOM_AD1 - -endif # TERRAFORM_OCI_REGION_BOM diff --git a/terraform/oci/kconfigs/regions/Kconfig.ca-montreal-1 b/terraform/oci/kconfigs/regions/Kconfig.ca-montreal-1 deleted file mode 100644 index ce71f531e..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.ca-montreal-1 +++ /dev/null @@ -1,28 +0,0 @@ -if TERRAFORM_OCI_REGION_YUL - -config TERRAFORM_OCI_REGION - string - output yaml - default "ca-montreal-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_YUL_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_YUL_AD1 - bool "1" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_YUL_AD1 - -endif # TERRAFORM_OCI_REGION_YUL diff --git a/terraform/oci/kconfigs/regions/Kconfig.ca-toronto-1 b/terraform/oci/kconfigs/regions/Kconfig.ca-toronto-1 deleted file mode 100644 index 16053e94e..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.ca-toronto-1 +++ /dev/null @@ -1,28 +0,0 @@ -if TERRAFORM_OCI_REGION_YYZ - -config TERRAFORM_OCI_REGION - string - output yaml - default "ca-toronto-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_YYZ_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_YYZ_AD1 - bool "1" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_YYZ_AD1 - -endif # TERRAFORM_OCI_REGION_YYZ diff --git a/terraform/oci/kconfigs/regions/Kconfig.us-ashburn-1 b/terraform/oci/kconfigs/regions/Kconfig.us-ashburn-1 deleted file mode 100644 index 9aa4d2714..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.us-ashburn-1 +++ /dev/null @@ -1,36 +0,0 @@ -if TERRAFORM_OCI_REGION_IAD - -config TERRAFORM_OCI_REGION - string - output yaml - default "us-ashburn-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_IAD_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_IAD_AD1 - bool "1" - -config TERRAFORM_OCI_REGION_IAD_AD2 - bool "2" - -config TERRAFORM_OCI_REGION_IAD_AD3 - bool "3" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_IAD_AD1 - default 2 if TERRAFORM_OCI_REGION_IAD_AD2 - default 3 if TERRAFORM_OCI_REGION_IAD_AD3 - -endif # TERRAFORM_OCI_REGION_IAD diff --git a/terraform/oci/kconfigs/regions/Kconfig.us-chicago-1 b/terraform/oci/kconfigs/regions/Kconfig.us-chicago-1 deleted file mode 100644 index 19c3b50c2..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.us-chicago-1 +++ /dev/null @@ -1,36 +0,0 @@ -if TERRAFORM_OCI_REGION_ORD - -config TERRAFORM_OCI_REGION - string - output yaml - default "us-chicago-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_ORD_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_ORD_AD1 - bool "1" - -config TERRAFORM_OCI_REGION_ORD_AD2 - bool "2" - -config TERRAFORM_OCI_REGION_ORD_AD3 - bool "3" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_ORD_AD1 - default 2 if TERRAFORM_OCI_REGION_ORD_AD2 - default 3 if TERRAFORM_OCI_REGION_ORD_AD3 - -endif # TERRAFORM_OCI_REGION_ORD diff --git a/terraform/oci/kconfigs/regions/Kconfig.us-phoenix-1 b/terraform/oci/kconfigs/regions/Kconfig.us-phoenix-1 deleted file mode 100644 index eb8021191..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.us-phoenix-1 +++ /dev/null @@ -1,36 +0,0 @@ -if TERRAFORM_OCI_REGION_PHX - -config TERRAFORM_OCI_REGION - string - output yaml - default "us-phoenix-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_PHX_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_PHX_AD1 - bool "1" - -config TERRAFORM_OCI_REGION_PHX_AD2 - bool "2" - -config TERRAFORM_OCI_REGION_PHX_AD3 - bool "3" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_PHX_AD1 - default 2 if TERRAFORM_OCI_REGION_PHX_AD2 - default 3 if TERRAFORM_OCI_REGION_PHX_AD3 - -endif # TERRAFORM_OCI_REGION_PHX diff --git a/terraform/oci/kconfigs/regions/Kconfig.us-sanjose-1 b/terraform/oci/kconfigs/regions/Kconfig.us-sanjose-1 deleted file mode 100644 index 69b4035f2..000000000 --- a/terraform/oci/kconfigs/regions/Kconfig.us-sanjose-1 +++ /dev/null @@ -1,28 +0,0 @@ -if TERRAFORM_OCI_REGION_SJC - -config TERRAFORM_OCI_REGION - string - output yaml - default "us-sanjose-1" - -choice - prompt "Availability Domain" - default TERRAFORM_OCI_REGION_SJC_AD1 - help - The number of the Availability Domain. This number - corresponds to the integer at the end of the Availability - Domain name. - - The OCI Fault Domain is chosen automatically. - -config TERRAFORM_OCI_REGION_SJC_AD1 - bool "1" - -endchoice - -config TERRAFORM_OCI_AD_NUMBER - int - output yaml - default 1 if TERRAFORM_OCI_REGION_SJC_AD1 - -endif # TERRAFORM_OCI_REGION_SJC diff --git a/terraform/oci/kconfigs/shapes/Kconfig.bm b/terraform/oci/kconfigs/shapes/Kconfig.bm deleted file mode 100644 index 40ef4502b..000000000 --- a/terraform/oci/kconfigs/shapes/Kconfig.bm +++ /dev/null @@ -1,83 +0,0 @@ -if TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL - -choice - prompt "OCI shape" - default TERRAFORM_OCI_SHAPE_BM_STANDARD3 - help - Select the basic hardware capabilities that are in each - instance. For more details, see: - - https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm#baremetalshapes - -config TERRAFORM_OCI_SHAPE_BM_STANDARD3 - bool "BM.Standard3" - depends on TARGET_ARCH_X86_64 - help - X9-based standard compute. Processor: Intel Xeon Platinum - 8358. Base frequency 2.6 GHz, max turbo frequency 3.4 GHz. - -config TERRAFORM_OCI_SHAPE_BM_STANDARD_E4 - bool "BM.Standard.E4" - depends on TARGET_ARCH_X86_64 - help - E4-based standard compute. Processor: AMD EPYC 7J13. Base - frequency 2.55 GHz, max boost frequency 3.5 GHz. - -config TERRAFORM_OCI_SHAPE_BM_STANDARD_E5 - bool "BM.Standard.E5" - depends on TARGET_ARCH_X86_64 - help - E5-based standard compute. Processor: AMD EPYC 9J14. Base - frequency 2.4 GHz, max boost frequency 3.7 GHz. - -config TERRAFORM_OCI_SHAPE_BM_STANDARD_A1 - bool "BM.Standard.A1" - depends on TARGET_ARCH_ARM64 - help - OCI Ampere A1 Compute Arm-based standard compute. Each - OCPU corresponds to a single hardware execution thread. - Processor: Ampere Altra Q80-30. Max frequency 3.0 GHz. - -config TERRAFORM_OCI_SHAPE_BM_DENSEIO_E4 - bool "BM.DenseIO.E4" - depends on TARGET_ARCH_X86_64 - help - E4-based dense I/O compute. Processor: AMD EPYC 7J13. - Base frequency 2.55 GHz, max boost frequency 3.5 GHz. - -config TERRAFORM_OCI_SHAPE_BM_DENSEIO_E5 - bool "BM.DenseIO.E5" - depends on TARGET_ARCH_X86_64 - help - E5-based dense I/O compute. Processor: AMD EPYC 9J14. - Base frequency 2.4 GHz, max boost frequency 3.7 GHz. - -config TERRAFORM_OCI_SHAPE_BM_OPTIMIZED3 - bool "BM.Optimized3" - depends on TARGET_ARCH_X86_64 - help - Processor: Intel Xeon 6354. Base frequency 3.0 GHz, max - turbo frequency 3.6 GHz. - -config TERRAFORM_OCI_SHAPE_BM_HPC_E5 - bool "BM.HPC.E5" - depends on TARGET_ARCH_X86_64 - help - Processor: AMD EPYC 9J14. Base frequency 2.4 GHz, max - boost frequency 3.7 GHz. - -endchoice - -config TERRAFORM_OCI_SHAPE - string - output yaml - default "BM.Standard3" if TERRAFORM_OCI_SHAPE_BM_STANDARD3 - default "BM.Standard.E4" if TERRAFORM_OCI_SHAPE_BM_STANDARD_E4 - default "BM.Standard.E5" if TERRAFORM_OCI_SHAPE_BM_STANDARD_E5 - default "BM.Standard.A1" if TERRAFORM_OCI_SHAPE_BM_STANDARD_A1 - default "BM.DenseIO.E4" if TERRAFORM_OCI_SHAPE_BM_DENSEIO_E4 - default "BM.DenseIO.E5" if TERRAFORM_OCI_SHAPE_BM_DENSEIO_E5 - default "BM.Optimized3" if TERRAFORM_OCI_SHAPE_BM_OPTIMIZED3 - default "BM.HPC.E5" if TERRAFORM_OCI_SHAPE_BM_HPC_E5 - -endif # TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL diff --git a/terraform/oci/kconfigs/shapes/Kconfig.flex b/terraform/oci/kconfigs/shapes/Kconfig.flex deleted file mode 100644 index 67d50604b..000000000 --- a/terraform/oci/kconfigs/shapes/Kconfig.flex +++ /dev/null @@ -1,104 +0,0 @@ -if TERRAFORM_OCI_SHAPE_FAMILY_FLEX - -choice - prompt "OCI shape" - default TERRAFORM_OCI_SHAPE_VM_STANDARD3_FLEX - help - Select the basic hardware capabilities that are in each - instance. For more detail, see: - - https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm#flexible - -config TERRAFORM_OCI_SHAPE_VM_STANDARD3_FLEX - bool "VM.Standard3.Flex" - depends on TARGET_ARCH_X86_64 - help - Selecting this option provisions each guest with between 1 - and 32 OCPUs (physical cores) and up to 512MB of memory. - -config TERRAFORM_OCI_SHAPE_VM_STANDARD_E4_FLEX - bool "VM.Standard.E4.Flex" - depends on TARGET_ARCH_X86_64 - help - Selecting this option provisions each guest with between 1 - and 114 OCPUs (physical AMD cores) and up to 1760MB of memory. - -config TERRAFORM_OCI_SHAPE_VM_STANDARD_E5_FLEX - bool "VM.Standard.E5.Flex" - depends on TARGET_ARCH_X86_64 - help - Selecting this option provisions each guest with between 1 - and 94 OCPUs (physical AMD cores) and up to 1048MB of memory. - -config TERRAFORM_OCI_SHAPE_VM_STANDARD_A1_FLEX - bool "VM.Standard.A1.Flex" - depends on TARGET_ARCH_ARM64 - help - Selecting this option provisions each guest with between 1 - and 80 OCPUs (physical ARM cores) and up to 512MB of memory. - -config TERRAFORM_OCI_SHAPE_VM_STANDARD_A2_FLEX - bool "VM.Standard.A2.Flex" - depends on TARGET_ARCH_ARM64 - help - Selecting this option provisions each guest with between 1 - and 78 OCPUs (physical ARM cores) and up to 946MB of memory. - -config TERRAFORM_OCI_SHAPE_VM_DENSEIO_E4_FLEX - bool "VM.DenseIO.E4.Flex" - depends on TARGET_ARCH_X86_64 - help - Selecting this option provisions each instance with either - 8 OCPUs and 128 GB memory, 16 OCPUs and 256 GB memory, or - 32 OCPUs and 512 GB memory. CPUs are based on the AMD - x86_64 platform. - -config TERRAFORM_OCI_SHAPE_VM_OPTIMIZED3_FLEX - bool "VM.Optimized3.Flex" - depends on TARGET_ARCH_X86_64 - help - Selecting this option provisions each instance with up to - 18 OCPUS. The memory provisioned for each instance is - typically matches a multiple of the number of OCPUS. - -endchoice - -config TERRAFORM_OCI_SHAPE - string - output yaml - default "VM.Standard3.Flex" if TERRAFORM_OCI_SHAPE_VM_STANDARD3_FLEX - default "VM.Standard.E4.Flex" if TERRAFORM_OCI_SHAPE_VM_STANDARD_E4_FLEX - default "VM.Standard.E5.Flex" if TERRAFORM_OCI_SHAPE_VM_STANDARD_E5_FLEX - default "VM.Standard.A1.Flex" if TERRAFORM_OCI_SHAPE_VM_STANDARD_A1_FLEX - default "VM.Standard.A2.Flex" if TERRAFORM_OCI_SHAPE_VM_STANDARD_A2_FLEX - default "VM.DenseIO.E4.Flex" if TERRAFORM_OCI_SHAPE_VM_DENSEIO_E4_FLEX - default "VM.Optimized3.Flex" if TERRAFORM_OCI_SHAPE_VM_OPTIMIZED3_FLEX - -config TERRAFORM_OCI_INSTANCE_FLEX_OCPUS - int "Instance CPU count" - output yaml - default 2 - help - The Oracle CPU (OCPU) represents physical CPU cores and is - the unit of measurement for CPUs on x86 CPUs (AMD and - Intel) and Arm CPUs (OCI Ampere Compute). A virtual CPU - (vCPU), the industry-standard for measuring compute - resources, represents one execution thread of a physical - CPU core. - - Most CPU architectures, including x86, runs two threads - per physical core, so one OCPU is the equal of two vCPUs - for x86-based compute. For OCI Compute, the minimum unit - of provisioning starts from one OCPU on both X86 (Intel - and AMD) and OCI Ampere Compute processors. - -config TERRAFORM_OCI_INSTANCE_FLEX_MEMORY_IN_GBS - int "Instance memory size" - output yaml - default 4 - help - Memory per instance, in GiBs. The minimum value for this - setting is a multiple of the number of OCPUS in each - instance. - -endif # TERRAFORM_OCI_SHAPE_FAMILY_FLEX diff --git a/terraform/oci/scripts/ad.j2 b/terraform/oci/scripts/ad.j2 new file mode 100644 index 000000000..8ff062ec6 --- /dev/null +++ b/terraform/oci/scripts/ad.j2 @@ -0,0 +1,42 @@ +if TERRAFORM_OCI_REGION_{{ region_code }} + +config TERRAFORM_OCI_REGION + string + output yaml + default "{{ region_name }}" + +choice + prompt "Availability Domain" + default TERRAFORM_OCI_REGION_{{ region_code }}_AD{{ ads[0]['number'] if ads else '1' }} + help + The number of the Availability Domain. This number + corresponds to the integer at the end of the Availability + Domain name. + + The OCI Fault Domain is chosen automatically. + +{% if ads %} +{% for ad in ads %} +config TERRAFORM_OCI_REGION_{{ region_code }}_AD{{ ad['number'] }} + bool "{{ ad['number'] }}" + +{% endfor %} +{% else %} +config TERRAFORM_OCI_REGION_{{ region_code }}_AD1 + bool "1" + +{% endif %} +endchoice + +config TERRAFORM_OCI_AD_NUMBER + int + output yaml +{% if ads %} +{% for ad in ads %} + default {{ ad['number'] }} if TERRAFORM_OCI_REGION_{{ region_code }}_AD{{ ad['number'] }} +{% endfor %} +{% else %} + default 1 +{% endif %} + +endif # TERRAFORM_OCI_REGION_{{ region_code }} diff --git a/terraform/oci/scripts/bare_metal_shapes.j2 b/terraform/oci/scripts/bare_metal_shapes.j2 new file mode 100644 index 000000000..771678a3e --- /dev/null +++ b/terraform/oci/scripts/bare_metal_shapes.j2 @@ -0,0 +1,69 @@ +if TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL + +choice + prompt "OCI shape" +{% if shapes and shapes | length > 0 %} + default TERRAFORM_OCI_SHAPE_{{ shapes[0]['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% else %} + default TERRAFORM_OCI_SHAPE_BM_STANDARD3 +{% endif %} + help + Select the basic hardware capabilities that are in each + instance. For more details, see: + + https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm#baremetalshapes + +{% for shape in shapes %} +{# Validate required fields are present #} +{% if 'shape_name' not in shape or 'cpu_isa' not in shape %} +{# Skip malformed shape entries #} +{% continue %} +{% endif %} +config TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} + bool "{{ shape['shape_name'] }}" +{% if shape['cpu_isa'] == 'x86_64' %} + depends on TARGET_ARCH_X86_64 +{% elif shape['cpu_isa'] == 'arm64' %} + depends on TARGET_ARCH_ARM64 +{% endif %} + help +{% if 'processor' in shape %} + Processor: {{ shape['processor'] }} +{% else %} + Bare metal instance. +{% endif %} +{% if shape.get('memory_gb', 'Flexible') != 'Flexible' and shape.get('ocpus', 'Flexible') != 'Flexible' %} + + OCPU count: {{ shape['ocpus'] }} + Memory: {{ shape['memory_gb'] }} GB +{% endif %} + Architecture: {{ shape['cpu_isa'] }} +{% if shape.get('network_performance', 'Not specified') != 'Not specified' %} + Network: {{ shape['network_performance'] }} +{% endif %} +{% if shape.get('storage', 'Block storage only') != 'Block storage only' %} + Local storage: {{ shape['storage'] }} +{% endif %} +{% if shape.get('gpu', 'None') != 'None' %} + GPU: {{ shape['gpu'] }} +{% endif %} +{% if shape.get('is_catalog_shape', False) %} + + NOTE: This shape may require service limit increases and may not + be available in all regions. Contact Oracle support to request + access if needed. +{% endif %} + +{% endfor %} +endchoice + +config TERRAFORM_OCI_SHAPE + string + output yaml +{% for shape in shapes %} +{% if 'shape_name' in shape and 'cpu_isa' in shape %} + default "{{ shape['shape_name'] }}" if TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% endif %} +{% endfor %} + +endif # TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL diff --git a/terraform/oci/scripts/catalog_shapes.yml b/terraform/oci/scripts/catalog_shapes.yml new file mode 100644 index 000000000..6c3b221e9 --- /dev/null +++ b/terraform/oci/scripts/catalog_shapes.yml @@ -0,0 +1,171 @@ +# OCI Catalog Shapes +# +# This file contains well-known OCI compute shapes that may not be visible +# via the OCI API. These shapes typically require service limit increases or +# are in limited availability. +# +# Purpose: +# The --include-catalog option in gen_kconfig_shape merges these shapes +# with API-discovered shapes to provide a complete menu of shapes that +# users can request access to. +# +# Canonical Sources: +# https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm +# (Official Oracle Cloud Infrastructure Compute Shapes documentation) +# +# Note: Shape availability varies by region and requires proper service +# limits. Use the OCI console to check availability and request limit +# increases if needed. +# +# Last Updated: 2025-10-21 +# Total Catalog Shapes: 11 +# +# Format: +# shape-name: +# architectures: [x86_64|arm64] +# is_flex: true|false # Optional, indicates flexible shapes +# is_bare_metal: true|false # Optional, indicates bare metal shapes +# has_gpu: true|false # Optional, indicates GPU shapes +# description: "Human-readable description" +# +# Selection Criteria for Catalog Shapes: +# --------------------------------------- +# A shape should be in this catalog if it meets these criteria: +# +# 1. NOT visible via standard OCI API query: +# $ cd terraform/oci/scripts +# $ ./gen_kconfig_shape --families --format raw +# If the shape family does NOT appear in the output, it's a catalog candidate. +# +# 2. Documented in Oracle's official compute shapes reference: +# https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm +# +# 3. Requires service limit increases or has limited regional availability: +# - DenseIO shapes (local NVMe storage) - often require limit increases +# - GPU shapes (NVIDIA GPUs) - limited availability, require special quotas +# - HPC shapes (high-performance computing) - specialty shapes with restrictions +# +# 4. Generally available (not preview/beta shapes that may be discontinued) +# +# How to update this file: +# ----------------------- +# When Oracle adds new shapes or you want to include additional catalog shapes: +# +# 1. Check if the shape is already API-visible in your tenancy: +# $ cd terraform/oci/scripts +# $ ./gen_kconfig_shape --families --format raw | grep -i "FAMILY_NAME" +# +# If found in API output, DO NOT add to catalog (API discovery handles it). +# If NOT found, proceed to step 2. +# +# 2. Verify the shape exists in Oracle's documentation: +# https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm +# +# Look for shape specifications including: +# - Architecture (x86_64 or arm64) +# - Whether it's Flex (flexible sizing) +# - Whether it's bare metal (BM prefix) +# - GPU information if applicable +# +# 3. Add the entry following the format specification above. +# +# Architecture detection rules: +# - Shapes with A1, A2 in name: arm64 (Ampere) +# - Shapes with AMD/Intel processors: x86_64 +# - Check Oracle docs if uncertain +# +# Type detection rules: +# - Name ends with .Flex: set is_flex: true +# - Name starts with BM.: set is_bare_metal: true +# - Contains GPU in name: set has_gpu: true +# +# 4. Update the "Last Updated" date and "Total Catalog Shapes" count above. +# +# 5. Test that the shape loads correctly: +# $ cd terraform/oci/scripts +# $ ./gen_kconfig_shape --include-catalog --families --format raw | grep "SHAPE_NAME" +# Verify the shape appears with a '*' indicating it's from the catalog. +# +# 6. Regenerate Kconfig.shape: +# $ ./gen_kconfig_shape --include-catalog > ../kconfigs/Kconfig.shape +# +# Example Decision Process: +# ------------------------- +# Q: Should I add VM.Standard.E5.Flex to the catalog? +# A: No. This shape is widely available and appears in standard API queries. +# Run ./gen_kconfig_shape --families to verify it's already discovered. +# +# Q: Should I add BM.GPU.H100.8 (hypothetical new GPU shape)? +# A: Yes, if: +# - It doesn't appear in ./gen_kconfig_shape --families output +# - It's documented at the Oracle reference URL above +# - It's a specialty shape (GPU = yes, requires quotas) +# +# Q: How do I know if a shape needs is_flex vs is_bare_metal? +# A: Check the shape name: +# - Ends with .Flex → is_flex: true +# - Starts with BM. → is_bare_metal: true +# - Can be both (e.g., BM.Something.Flex would have both set to true) +# +# Catalog Shape Definitions: +# -------------------------- + +# DenseIO Shapes - High I/O with local NVMe storage +VM.DenseIO.E4.Flex: + architectures: [x86_64] + is_flex: true + description: "DenseIO E4 Flex with local NVMe storage" + +BM.DenseIO1.36: + architectures: [x86_64] + is_bare_metal: true + description: "DenseIO1 bare metal with local NVMe storage" + +BM.DenseIO2.52: + architectures: [x86_64] + is_bare_metal: true + description: "DenseIO2 bare metal with local NVMe storage" + +VM.DenseIO.A2.Flex: + architectures: [arm64] + is_flex: true + description: "DenseIO A2 Flex ARM with local NVMe storage" + +# GPU Shapes - For AI/ML and graphics workloads +VM.GPU.A10.1: + architectures: [x86_64] + has_gpu: true + description: "1x NVIDIA A10 GPU" + +VM.GPU.A10.2: + architectures: [x86_64] + has_gpu: true + description: "2x NVIDIA A10 GPUs" + +BM.GPU.A10.4: + architectures: [x86_64] + is_bare_metal: true + has_gpu: true + description: "4x NVIDIA A10 GPUs" + +BM.GPU4.8: + architectures: [x86_64] + is_bare_metal: true + has_gpu: true + description: "8x NVIDIA A100 GPUs" + +VM.GPU.GU1.1: + architectures: [x86_64] + has_gpu: true + description: "1x NVIDIA P100 GPU" + +VM.GPU.GU1.2: + architectures: [x86_64] + has_gpu: true + description: "2x NVIDIA P100 GPUs" + +BM.GPU.GM4.8: + architectures: [x86_64] + is_bare_metal: true + has_gpu: true + description: "8x NVIDIA V100 GPUs" diff --git a/terraform/oci/scripts/fixed_shapes.j2 b/terraform/oci/scripts/fixed_shapes.j2 new file mode 100644 index 000000000..3b2be1bc4 --- /dev/null +++ b/terraform/oci/scripts/fixed_shapes.j2 @@ -0,0 +1,70 @@ +if TERRAFORM_OCI_SHAPE_FAMILY_FIXED + +choice + prompt "OCI shape" +{% if shapes and shapes | length > 0 %} + default TERRAFORM_OCI_SHAPE_{{ shapes[0]['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% else %} + default TERRAFORM_OCI_SHAPE_VM_STANDARD2_1 +{% endif %} + help + Select the specific shape configuration. Fixed shapes have + predetermined OCPU and memory configurations optimized for + common workload patterns. For more details, see: + + https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm + +{% for shape in shapes %} +{# Validate required fields are present and have valid values for fixed shapes #} +{% if 'shape_name' not in shape or 'ocpus' not in shape or 'memory_gb' not in shape or 'cpu_isa' not in shape %} +{# Skip malformed shape entries #} +{% continue %} +{% endif %} +{% if shape['ocpus'] == 'Flexible' or shape['memory_gb'] == 'Flexible' %} +{# Skip flex shapes that were incorrectly categorized as fixed #} +{% continue %} +{% endif %} +config TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} + bool "{{ shape['shape_name'] }}" +{% if shape['cpu_isa'] == 'x86_64' %} + depends on TARGET_ARCH_X86_64 +{% elif shape['cpu_isa'] == 'arm64' %} + depends on TARGET_ARCH_ARM64 +{% endif %} + help +{% if 'processor' in shape %} + Processor: {{ shape['processor'] }} + +{% endif %} + OCPU count: {{ shape['ocpus'] }} + Memory: {{ shape['memory_gb'] }} GB + Architecture: {{ shape['cpu_isa'] }} +{% if shape.get('network_performance', 'Not specified') != 'Not specified' %} + Network: {{ shape['network_performance'] }} +{% endif %} +{% if shape.get('storage', 'Block storage only') != 'Block storage only' %} + Local storage: {{ shape['storage'] }} +{% endif %} +{% if shape.get('gpu', 'None') != 'None' %} + GPU: {{ shape['gpu'] }} +{% endif %} +{% if shape.get('is_catalog_shape', False) %} + + NOTE: This shape may require service limit increases and may not + be available in all regions. Contact Oracle support to request + access if needed. +{% endif %} + +{% endfor %} +endchoice + +config TERRAFORM_OCI_SHAPE + string + output yaml +{% for shape in shapes %} +{% if 'shape_name' in shape and 'ocpus' in shape and 'memory_gb' in shape and shape['ocpus'] != 'Flexible' and shape['memory_gb'] != 'Flexible' %} + default "{{ shape['shape_name'] }}" if TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% endif %} +{% endfor %} + +endif # TERRAFORM_OCI_SHAPE_FAMILY_FIXED diff --git a/terraform/oci/scripts/flex_shapes.j2 b/terraform/oci/scripts/flex_shapes.j2 new file mode 100644 index 000000000..be2c2197c --- /dev/null +++ b/terraform/oci/scripts/flex_shapes.j2 @@ -0,0 +1,97 @@ +if TERRAFORM_OCI_SHAPE_FAMILY_FLEX + +choice + prompt "OCI shape" +{% if shapes and shapes | length > 0 %} + default TERRAFORM_OCI_SHAPE_{{ shapes[0]['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% else %} + default TERRAFORM_OCI_SHAPE_VM_STANDARD3_FLEX +{% endif %} + help + Select the basic hardware capabilities that are in each + instance. For more detail, see: + + https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm#flexible + +{% for shape in shapes %} +{# Validate required fields are present #} +{% if 'shape_name' not in shape or 'cpu_isa' not in shape %} +{# Skip malformed shape entries #} +{% continue %} +{% endif %} +config TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} + bool "{{ shape['shape_name'] }}" +{% if shape['cpu_isa'] == 'x86_64' %} + depends on TARGET_ARCH_X86_64 +{% elif shape['cpu_isa'] == 'arm64' %} + depends on TARGET_ARCH_ARM64 +{% endif %} + help + {{ shape['processor'] if 'processor' in shape else 'Flexible shape: OCPU and memory can be customized.' }} + +{% if 'ocpu_min' in shape and 'ocpu_max' in shape %} + OCPU range: {{ shape['ocpu_min'] }} to {{ shape['ocpu_max'] }} +{% endif %} +{% if 'memory_per_ocpu_min' in shape and 'memory_per_ocpu_max' in shape %} + Memory per OCPU: {{ shape['memory_per_ocpu_min'] }} to {{ shape['memory_per_ocpu_max'] }} GB +{% endif %} +{% if 'memory_min' in shape and 'memory_max' in shape %} + Total memory range: {{ shape['memory_min'] }} to {{ shape['memory_max'] }} GB +{% endif %} + Architecture: {{ shape['cpu_isa'] }} +{% if shape.get('network_performance', 'Not specified') != 'Not specified' %} + Network: {{ shape['network_performance'] }} +{% endif %} +{% if shape.get('storage', 'Block storage only') != 'Block storage only' %} + Local storage: {{ shape['storage'] }} +{% endif %} +{% if shape.get('gpu', 'None') != 'None' %} + GPU: {{ shape['gpu'] }} +{% endif %} +{% if shape.get('is_catalog_shape', False) %} + + NOTE: This shape may require service limit increases and may not + be available in all regions. Contact Oracle support to request + access if needed. +{% endif %} + +{% endfor %} +endchoice + +config TERRAFORM_OCI_SHAPE + string + output yaml +{% for shape in shapes %} +{% if 'shape_name' in shape and 'cpu_isa' in shape %} + default "{{ shape['shape_name'] }}" if TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% endif %} +{% endfor %} + +config TERRAFORM_OCI_INSTANCE_FLEX_OCPUS + int "Instance CPU count" + output yaml + default 2 + help + The Oracle CPU (OCPU) represents physical CPU cores and is + the unit of measurement for CPUs on x86 CPUs (AMD and + Intel) and Arm CPUs (OCI Ampere Compute). A virtual CPU + (vCPU), the industry-standard for measuring compute + resources, represents one execution thread of a physical + CPU core. + + Most CPU architectures, including x86, run two threads + per physical core, so one OCPU is the equal of two vCPUs + for x86-based compute. For OCI Compute, the minimum unit + of provisioning starts from one OCPU on both X86 (Intel + and AMD) and OCI Ampere Compute processors. + +config TERRAFORM_OCI_INSTANCE_FLEX_MEMORY_IN_GBS + int "Instance memory size" + output yaml + default 4 + help + Memory per instance, in GiBs. The minimum value for this + setting is a multiple of the number of OCPUs in each + instance. + +endif # TERRAFORM_OCI_SHAPE_FAMILY_FLEX diff --git a/terraform/oci/scripts/gen_kconfig_image b/terraform/oci/scripts/gen_kconfig_image new file mode 100755 index 000000000..977446fd0 --- /dev/null +++ b/terraform/oci/scripts/gen_kconfig_image @@ -0,0 +1,802 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +""" +Retrieve compute image information from OCI. Use it to construct the "images" +Kconfig menu. + +OCI images are OS templates that can be used to launch compute instances. +This script queries the OCI API to discover available images and generates +Kconfig menu entries for them. + +Publisher Definitions: + Publisher definitions (e.g., "Oracle Linux", "Ubuntu") are maintained + in the publisher_definitions.yml file in the same directory as this + script. This makes it easier to update publisher information when Oracle + adds new distributions or when you want to customize display names and + priorities. + + To update publisher definitions: + 1. Edit terraform/oci/scripts/publisher_definitions.yml + 2. Add or modify entries following the existing format + 3. Run this script to regenerate Kconfig.images + + The YAML file contains detailed instructions for how to add new + publisher definitions. If the YAML file is not found, the script + falls back to dynamic publisher discovery by analyzing image names. + +Image Discovery: + By default, this script aggregates images from all subscribed regions to + provide a comprehensive mapping of image OCIDs across regions. + + This script focuses exclusively on OCI platform images (official + Oracle-provided images). Marketplace and community images are not + included in the automated discovery, though users can still specify + marketplace image OCIDs manually via the "Custom image OCID" option. + + The script discovers Linux distribution platform images using: + - Known publishers defined in publisher_definitions.yml + - Dynamic discovery that detects new distributions automatically + +Usage: + # Generate images Kconfig from all subscribed regions (default) + ./gen_kconfig_image > ../kconfigs/Kconfig.images + + # List all available OS publishers + ./gen_kconfig_image --publishers + + # Get details for a specific publisher + ./gen_kconfig_image oracle +""" + +import sys +import os +import argparse +import re +from collections import defaultdict + +from oci_common import ( + get_default_region, + get_default_compartment, + get_subscribed_regions, + get_jinja2_environment, + load_yaml_config, + create_identity_client, + create_compute_client, + get_all_region_keys, + get_region_kconfig_name, +) + +# Cache for loaded publisher definitions (loaded once per script execution) +_cached_publishers = None +_publishers_load_attempted = False + + +def discover_publishers_from_images(images, quiet=False): + """ + Dynamically discover Linux publishers from image display names. + + This function analyzes image names to find publishers beyond the + hard-coded list, enabling automatic discovery of new Linux distributions. + + Args: + images (list): List of OCI image objects + quiet (bool): Suppress debug messages + + Returns: + dict: Dictionary of discovered publisher patterns + """ + discovered = {} + seen_patterns = defaultdict(set) + + # Patterns to check for potential new Linux distributions + # Format: (regex_pattern, key, publisher_name, description) + # Only match distributions with "Linux" in the name - this is self-filtering + # and doesn't require explicit exclusion of non-Linux systems + discovery_patterns = [ + (r"^([\w\-]+)-Linux-", None, None, "Linux"), + ] + + for image in images: + display_name = image.display_name + + # Check for Linux patterns + for pattern_regex, _, _, suffix in discovery_patterns: + match = re.match(pattern_regex, display_name, re.IGNORECASE) + if match: + publisher_prefix = match.group(1).lower() + + # Skip if we already know this publisher + known_publishers = get_known_publishers() + if publisher_prefix in known_publishers: + continue + + # Create a key for this publisher + if publisher_prefix not in discovered: + # Capitalize properly for display + display_name_parts = publisher_prefix.split("-") + publisher_display = " ".join( + part.capitalize() for part in display_name_parts + ) + + discovered[publisher_prefix] = { + "publisher_name": publisher_display, + "description": f"{publisher_display} {suffix}", + "display_name_patterns": [], + "priority": 100, # Lower priority for discovered + "discovered": True, # Mark as dynamically discovered + } + + # Add the pattern for this publisher + pattern_str = f"{match.group(1)}-.*" + seen_patterns[publisher_prefix].add(pattern_str) + + # Update discovered publishers with their patterns + for key, patterns in seen_patterns.items(): + if key in discovered: + discovered[key]["display_name_patterns"] = list(patterns) + + if not quiet and discovered: + print( + f"Dynamically discovered {len(discovered)} new Linux publisher(s):", + file=sys.stderr, + ) + for key, info in discovered.items(): + print( + f" - {info['publisher_name']}: {info['description']}", file=sys.stderr + ) + + return discovered + + +def get_known_publishers(): + """ + Get dictionary of known OS image publishers in OCI. + + Publisher definitions are loaded from publisher_definitions.yml to make + it easier to update when Oracle adds new Linux distributions or when you + want to customize publisher priorities and naming. + + The YAML file contains publisher information including: + - publisher_name: Display name for the publisher/company + - description: Full description used in Kconfig help text + - display_name_patterns: List of regex patterns to match image names + - priority: Display order (lower numbers appear first) + + If the YAML file is not found or fails to parse, an empty dictionary + is returned and the script relies on dynamic publisher discovery via + discover_publishers_from_images() to identify Linux distributions. + + The publishers are cached after first load to avoid repeated file I/O + and duplicate warnings. + + To update the publisher definitions: + 1. Edit terraform/oci/scripts/publisher_definitions.yml + 2. Add or modify entries following the existing format + 3. Regenerate Kconfig.images by running this script + + See publisher_definitions.yml for detailed update instructions. + + Returns: + dict: Dictionary mapping publisher keys to publisher information, + or empty dict if YAML is unavailable (dynamic discovery + will be used instead) + """ + global _cached_publishers, _publishers_load_attempted + + # Return cached result if already loaded + if _publishers_load_attempted: + return _cached_publishers if _cached_publishers else {} + + # Mark that we've attempted to load (even if it fails) + _publishers_load_attempted = True + + _cached_publishers = load_yaml_config("publisher_definitions.yml", quiet=True) + if not _cached_publishers: + print( + "Warning: publisher_definitions.yml not found or empty. " + "Relying on dynamic publisher discovery.", + file=sys.stderr, + ) + return _cached_publishers + + +def get_image_type_description(listing_type): + """ + Convert OCI listing_type to user-friendly description. + + Note: This script only processes platform images (listing_type "NONE" or None). + + Args: + listing_type (str): OCI image listing_type + + Returns: + str: User-friendly description + """ + if listing_type == "NONE" or listing_type is None: + return "Platform image" + else: + # Unexpected listing type - should not happen with platform-only images + return f"Image ({listing_type})" + + +def get_all_images(compartment_ocid, regions=None, quiet=False): + """ + Get all available platform images across specified regions with dynamic + publisher discovery. + + This enhanced version discovers new Linux publishers dynamically while + fetching images. + + Args: + compartment_ocid (str): OCI compartment OCID + regions (list): List of region names to query. If None, uses default region. + quiet (bool): Suppress debug messages + + Returns: + tuple: (images_dict, all_publishers) where: + - images_dict: Dictionary mapping (display_name, arch) to region->ocid mappings + - all_publishers: Combined dictionary of known and discovered publishers + """ + # Lazy import of OCI exceptions - only needed when actually using OCI API + from oci.exceptions import ServiceError, ConfigFileNotFound + + if regions is None: + regions = [get_default_region()] + + # Store images as: {(display_name, arch): {region: ocid, listing_type: type}} + all_images = defaultdict(lambda: {"regions": {}, "listing_type": None}) + all_image_objects = [] # Keep track of image objects for discovery + + for region in regions: + if not quiet: + print(f"Fetching images from {region}...", file=sys.stderr) + + try: + compute = create_compute_client(region) + + images_response = compute.list_images( + compartment_ocid, sort_by="DISPLAYNAME", sort_order="ASC" + ) + images = images_response.data + all_image_objects.extend(images) # Collect for publisher discovery + + # First pass: collect all images (we'll filter after discovery) + for image in images: + display_name = image.display_name + arch = get_image_architecture(display_name) + key = (display_name, arch) + all_images[key]["regions"][region] = image.id + # Capture listing_type (should be same across regions for same image) + if all_images[key]["listing_type"] is None: + all_images[key]["listing_type"] = getattr( + image, "listing_type", None + ) + + except ConfigFileNotFound: + print( + "Error: OCI config file not found. Please configure OCI CLI.", + file=sys.stderr, + ) + return {}, {} + except ServiceError as e: + print(f" Warning: Could not query {region}: {e.message}", file=sys.stderr) + continue + except Exception as e: + print(f" Warning: Error querying {region}: {e}", file=sys.stderr) + continue + + # Discover new publishers from the collected images + discovered_publishers = discover_publishers_from_images(all_image_objects, quiet) + + # Merge known and discovered publishers + all_publishers = get_known_publishers() + all_publishers.update(discovered_publishers) + + # Now filter images based on all publishers (known + discovered) + filtered_images = defaultdict(lambda: {"regions": {}, "listing_type": None}) + recognized_count = 0 + + for (display_name, arch), image_data in all_images.items(): + if is_recognized_image(display_name, all_publishers): + filtered_images[(display_name, arch)] = image_data + recognized_count += 1 + + if not quiet: + print( + f"\nTotal publishers: {len(all_publishers)} " + f"({len(discovered_publishers)} discovered)", + file=sys.stderr, + ) + print(f"Total recognized Linux images: {recognized_count}", file=sys.stderr) + + return filtered_images, all_publishers + + +def is_recognized_image(display_name, publishers): + """ + Check if an image display name matches any publisher patterns. + + All publisher patterns are Linux-specific, so no explicit exclusion + of non-Linux systems is needed. + + Args: + display_name (str): Image display name + publishers (dict): Dictionary of publisher information + + Returns: + bool: True if image is recognized + """ + for publisher_info in publishers.values(): + for pattern in publisher_info["display_name_patterns"]: + if re.match(pattern, display_name, re.IGNORECASE): + return True + return False + + +def get_image_architecture(display_name): + """ + Infer image architecture from display name. + + Args: + display_name (str): Image display name + + Returns: + str: 'x86_64' or 'arm64' + """ + display_lower = display_name.lower() + if "aarch64" in display_lower or "arm64" in display_lower: + return "arm64" + elif "gpu" in display_lower or "gen2-gpu" in display_lower: + return "x86_64" # GPU instances are x86_64 + else: + return "x86_64" # Default to x86_64 + + +def classify_image(display_name, publishers): + """ + Classify an image into publisher and version groups using dynamic publishers. + + Args: + display_name (str): Image display name + publishers (dict): Dictionary of publisher information + + Returns: + tuple: (publisher_key, version_key, friendly_name, full_display_name) + """ + display_lower = display_name.lower() + + # Check each publisher's patterns + for pub_key, pub_info in publishers.items(): + for pattern in pub_info["display_name_patterns"]: + if re.match(pattern, display_name, re.IGNORECASE): + # Found a matching publisher + # Extract version using the publisher's pattern as a guide + # Convert pattern like "Oracle-Linux-.*" to "Oracle-Linux-" + # Then look for version number immediately after this prefix + version_match = None + + # Try to extract the prefix from the pattern (remove wildcards) + prefix = pattern.replace(".*", "").replace("\\d+", "").replace("-$", "") + if prefix: + # Look for version after the prefix: prefix-X.Y or prefix X.Y + version_pattern = rf"{re.escape(prefix)}[-\s](\d+(?:\.\d+)?)" + version_match = re.search( + version_pattern, display_name, re.IGNORECASE + ) + + # Fallback: match version numbers followed by a hyphen + # This matches platform images (e.g., "Oracle-Linux-9.6-2025...") + if not version_match: + version_match = re.search(r"(\d+(?:\.\d+)?)-", display_name) + + if version_match: + version = version_match.group(1).replace(".", "_") + + # Determine architecture variant + variant = "" + if "gen2-gpu" in display_lower: + variant = "_GPU" + elif "aarch64" in display_lower or "arm64" in display_lower: + variant = "_ARM64" + else: + variant = "_X86" + + # Create version key + version_key = f"{pub_key.upper()}_{version}{variant}" + + # Create friendly name + friendly_name = ( + f"{pub_info['description']} {version_match.group(1)}" + ) + if variant == "_GPU": + friendly_name += " Gen2 GPU" + elif variant == "_ARM64": + friendly_name += " (aarch64)" + elif variant == "_X86": + friendly_name += " (x86)" + + # Add discovered marker if applicable + if pub_info.get("discovered"): + friendly_name += " [NEW]" + + return (pub_key, version_key, friendly_name, display_name) + + return (None, None, None, None) + + +def organize_images_by_publisher(images_dict, publishers, quiet=False): + """ + Organize images by publisher and version using dynamic publishers. + + Args: + images_dict (dict): Dictionary from get_all_images() + publishers (dict): Dictionary of publisher information + quiet (bool): Suppress debug messages + + Returns: + dict: Organized structure {publisher: {version_key: {regions, display_name, ...}}} + """ + organized = defaultdict(lambda: defaultdict(dict)) + + for (display_name, arch), image_data in images_dict.items(): + publisher_key, version_key, friendly_name, full_display_name = classify_image( + display_name, publishers + ) + + if not publisher_key or not version_key: + continue + + # Extract region OCIDs and listing type from the data structure + region_ocids = image_data["regions"] + listing_type = image_data.get("listing_type") + + # Multiple platform images may map to same version_key with different + # release dates (e.g., Oracle-Linux-9.5-2024.01.01 and 9.5-2024.02.01). + # Keep the newest image by comparing release dates in display names. + if version_key in organized[publisher_key]: + existing_display_name = organized[publisher_key][version_key][ + "display_name" + ] + # Extract dates from display names (format: YYYY.MM.DD) + # Dates are alphabetically sortable, so simple string comparison works + if display_name <= existing_display_name: + # Current image is older or same, keep existing + continue + # Current image is newer, replace existing (fall through to store) + + # Store image information + organized[publisher_key][version_key] = { + "friendly_name": friendly_name, + "display_name": full_display_name, + "architecture": arch, + "region_ocids": region_ocids, + "listing_type": listing_type, + "image_type": get_image_type_description(listing_type), + } + + if not quiet: + for publisher, versions in organized.items(): + pub_info = publishers.get(publisher, {}) + status = " (discovered)" if pub_info.get("discovered") else "" + print( + f"Publisher '{publisher}'{status}: {len(versions)} versions", + file=sys.stderr, + ) + + return organized + + +def get_release_notes_url(display_name): + """ + Generate the Oracle Cloud documentation URL for an image's release notes. + + Args: + display_name (str): Image display name + + Returns: + str: URL to release notes or empty string if not applicable + """ + # Convert display name to URL-friendly format + # Example: Oracle-Linux-9.6-2025.06.17-0 -> + # oracle-linux-9-6-2025-06-17-0 + url_slug = display_name.lower() + url_slug = url_slug.replace("canonical-ubuntu-", "ubuntu-") + url_slug = url_slug.replace(".", "-") + + # Determine the base path + if "oracle-linux" in display_name.lower(): + # Determine major version for URL path + version_match = re.search(r"(\d+)\.", display_name) + if version_match: + major_version = version_match.group(1) + return f"https://docs.oracle.com/en-us/iaas/images/oracle-linux-{major_version}x/{url_slug}.htm" + elif "ubuntu" in display_name.lower(): + # Determine version for URL path (2004, 2204, 2404) + version_match = re.search(r"(\d+)\.(\d+)", display_name) + if version_match: + major = version_match.group(1) + minor = version_match.group(2) + version_str = f"{major}{minor}" + return f"https://docs.oracle.com/en-us/iaas/images/ubuntu-{version_str}/{url_slug}.htm" + + return "" + + +def output_images_kconfig(organized_images, publishers, regions, region_key_map): + """ + Output images menu in Kconfig format with dynamic publishers. + + Args: + organized_images (dict): Organized images from organize_images_by_publisher() + publishers (dict): Dictionary of all publishers (known + discovered) + regions (list): List of region names that were queried + region_key_map (dict): Mapping from region_name to region_key + """ + # Output header comment showing which regions were queried + print("# This file was auto-generated by gen_kconfig_image") + print("# Queried OCI regions: " + ", ".join(sorted(regions))) + print("#") + print("# Note: Images may not be available in regions not listed above.") + print("# See individual image help text for specific region availability.") + print() + + environment = get_jinja2_environment() + + # Sort publishers by priority for consistent ordering + sorted_publishers = sorted( + [(k, v) for k, v in publishers.items() if k in organized_images], + key=lambda x: (x[1].get("priority", 100), x[0]), + ) + + # Output the top-level distribution choice menu + template = environment.get_template("image_distributions.j2") + print( + template.render( + publishers=[pub[0] for pub in sorted_publishers], + ) + ) + print() + + # Create a lambda that uses the region_key_map + def get_kconfig_name(region_name): + return get_region_kconfig_name(region_name, region_key_map) + + def version_sort_key(version_item): + """ + Extract numeric version from version_key for proper chronological sorting. + + Version keys are like: ORACLE_9_6_X86, UBUNTU_22_04_ARM64 + Sort by numeric version (oldest to newest), not alphabetic. + """ + version_key, version_data = version_item + parts = version_key.split("_") + + # Remove publisher prefix, leaving version numbers and architecture + # Could be: [major, minor, arch] or [major, arch] + version_parts = parts[1:] + + major = 0 + minor = 0 + + # The last part is usually the architecture (X86, ARM64, GPU) + # Everything before that is version numbers + if len(version_parts) >= 2: + try: + major = int(version_parts[0]) + # Try to parse second part as minor version + if len(version_parts) >= 3: + try: + minor = int(version_parts[1]) + except ValueError: + # Second part is arch, no minor version + minor = 0 + except ValueError: + pass + + # Architecture preference: X86, ARM64, GPU for consistent ordering + arch_order = {"X86": 0, "ARM64": 1, "GPU": 2} + arch = version_parts[-1] if version_parts else "X86" + arch_priority = arch_order.get(arch, 99) + + return (major, minor, arch_priority) + + # Output each publisher's images + template = environment.get_template("image_publisher.j2") + for publisher_key, publisher_info in sorted_publishers: + versions = organized_images.get(publisher_key, {}) + + # Sort versions numerically (oldest to newest) + sorted_versions = sorted(versions.items(), key=version_sort_key) + + # Add discovered marker to description if applicable + description = publisher_info.get("description", publisher_key) + if publisher_info.get("discovered"): + description += " (Discovered)" + + print( + template.render( + publisher_key=publisher_key, + publisher_name=publisher_info.get("publisher_name", publisher_key), + publisher_description=description, + versions=sorted_versions, + get_release_notes_url=get_release_notes_url, + get_region_kconfig_name=get_kconfig_name, + ) + ) + print() + + +def output_publishers_raw(quiet=False): + """Output available publishers in table format.""" + publishers = get_known_publishers() + + if not quiet: + print(f"Known OS image publishers ({len(publishers)}):\n") + + print(f"{'Publisher Key':<15} {'Publisher Name':<20} {'Description':<30}") + print("-" * 70) + + for key, info in publishers.items(): + print( + f"{key:<15} " f"{info['publisher_name']:<20} " f"{info['description']:<30}" + ) + + +def output_publisher_raw(publisher_key, organized_images, quiet=False): + """Output publisher image information in table format.""" + publishers = get_known_publishers() + publisher_info = publishers.get(publisher_key, {}) + + if not quiet: + print(f"Images for {publisher_info.get('publisher_name', publisher_key)}") + print(f"Description: {publisher_info.get('description', '')}\n") + + versions = organized_images.get(publisher_key, {}) + if not versions: + print(f"No images found for publisher '{publisher_key}'.") + return + + print(f"{'Version':<40} {'Architecture':<15} {'Regions':<10}") + print("-" * 70) + + for version_key, version_info in sorted(versions.items()): + region_count = len(version_info["region_ocids"]) + print( + f"{version_info['friendly_name']:<40} " + f"{version_info['architecture']:<15} " + f"{region_count:<10}" + ) + + +def parse_arguments(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Get OCI compute image information and generate Kconfig", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Generate Kconfig from all subscribed regions (default) + python %(prog)s > ../kconfigs/Kconfig.images + + # List available publishers + python %(prog)s --publishers + + # Get details for a specific publisher + python %(prog)s oracle --format raw + + # Query specific region only + python %(prog)s --region us-chicago-1 + """, + ) + parser.add_argument( + "publisher_key", nargs="?", help="Publisher key (e.g., oracle, ubuntu)" + ) + + parser.add_argument( + "--publishers", action="store_true", help="List all known publishers" + ) + parser.add_argument( + "--format", + "-f", + choices=["raw", "kconfig"], + default="kconfig", + help="Output format (default: kconfig)", + ) + parser.add_argument( + "--quiet", "-q", action="store_true", help="Suppress informational messages" + ) + parser.add_argument( + "--region", + "-r", + help="Query specific region only (default: aggregate from all subscribed regions)", + ) + return parser.parse_args() + + +def main(): + """Main function to run the program.""" + args = parse_arguments() + + if args.publishers: + # Show both known and discovered publishers + compartment_ocid = get_default_compartment() + if compartment_ocid: + # Get one region's images to discover publishers + region = get_default_region() + images_dict, all_publishers = get_all_images( + compartment_ocid, [region], True + ) # Quiet mode for discovery + + print("Known and Discovered Linux Publishers:") + print("-" * 70) + print( + f"{'Publisher Key':<15} {'Publisher Name':<20} {'Description':<25} {'Status':<10}" + ) + print("-" * 70) + + sorted_pubs = sorted( + all_publishers.items(), key=lambda x: (x[1].get("priority", 100), x[0]) + ) + for key, info in sorted_pubs: + status = "Discovered" if info.get("discovered") else "Built-in" + print( + f"{key:<15} " + f"{info['publisher_name']:<20} " + f"{info['description']:<25} " + f"{status:<10}" + ) + else: + output_publishers_raw(args.quiet) + return + + compartment_ocid = get_default_compartment() + if not compartment_ocid: + print("Error: Could not determine compartment OCID", file=sys.stderr) + sys.exit(1) + + # Get region key mappings from OCI API + region_key_map = get_all_region_keys(args.quiet) + + # Determine which regions to query + if args.region: + regions = [args.region] + else: + regions = get_subscribed_regions(args.quiet) + + # Get platform images from OCI API with dynamic publisher discovery + images_dict, all_publishers = get_all_images(compartment_ocid, regions, args.quiet) + + if not images_dict: + print("Error: No images found", file=sys.stderr) + sys.exit(1) + + # Organize images by publisher using discovered publishers + organized_images = organize_images_by_publisher( + images_dict, all_publishers, args.quiet + ) + + if args.publisher_key: + if args.publisher_key not in organized_images: + print(f"Error: Unknown publisher '{args.publisher_key}'", file=sys.stderr) + print( + f"Available publishers: {', '.join(organized_images.keys())}", + file=sys.stderr, + ) + sys.exit(1) + + if args.format == "raw": + output_publisher_raw(args.publisher_key, organized_images, args.quiet) + else: + # For Kconfig format of single publisher, output full menu + output_images_kconfig( + organized_images, all_publishers, regions, region_key_map + ) + return + + # Output full Kconfig menu with dynamic publishers + output_images_kconfig(organized_images, all_publishers, regions, region_key_map) + + +if __name__ == "__main__": + main() diff --git a/terraform/oci/scripts/gen_kconfig_location b/terraform/oci/scripts/gen_kconfig_location new file mode 100755 index 000000000..17ec8266c --- /dev/null +++ b/terraform/oci/scripts/gen_kconfig_location @@ -0,0 +1,476 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +""" +Retrieve region and availability domain information from OCI. Use +it to construct the "locations" Kconfig menu. + +Region Friendly Names: + Region friendly names (e.g., "US Midwest (Chicago)") are maintained + in the region_friendly_names.yml file in the same directory as this + script. This makes it easier to update the friendly names when Oracle + adds new regions or when you want to customize the display names. + + To update region friendly names: + 1. Edit terraform/oci/scripts/region_friendly_names.yml + 2. Add or modify entries following the existing format + 3. Run this script to regenerate Kconfig.location + + The YAML file contains detailed instructions for how to find and add + new region information. If a region is not found in the YAML file, + the script will auto-generate a friendly name from the region identifier. + +Usage: + # Generate complete Kconfig.location file + ./gen_kconfig_location > ../kconfigs/Kconfig.location + + # List all available regions + ./gen_kconfig_location --regions + + # Get details for a specific region + ./gen_kconfig_location us-chicago-1 +""" + +import os +import sys +import argparse + +import oci +from oci.exceptions import ServiceError + +from oci_common import ( + get_default_region, + get_jinja2_environment, + load_yaml_config, + create_identity_client, + get_oci_config, +) + + +def load_region_friendly_names(): + """ + Load region friendly names from the YAML configuration file. + + The friendly names are maintained in region_friendly_names.yml to make + it easier to update when Oracle adds new regions. The YAML file contains + the canonical mapping from OCI region identifiers to human-readable + display names. + + To update the friendly names: + 1. Edit terraform/oci/scripts/region_friendly_names.yml + 2. Add or modify entries following the existing format + 3. Regenerate Kconfig.location by running this script + + See region_friendly_names.yml for detailed update instructions. + + Returns: + dict: Dictionary mapping region names to friendly display names + """ + return load_yaml_config("region_friendly_names.yml") + + +def get_region_code(regions, region_name): + """ + Get the 3-letter code for a region by looking it up in the regions list. + + Args: + regions (list): List of region dictionaries + region_name (str): OCI region name (e.g., 'us-chicago-1') + + Returns: + str: 3-letter code (e.g., 'ORD') from OCI's official region_key + """ + for region in regions: + if region["region_name"] == region_name: + return region["region_code"] + + # Fallback if region not found (should not happen in normal operation) + # Take first 3 letters of the location part + parts = region_name.split("-") + if len(parts) >= 2: + return parts[1][:3].upper() + return region_name[:3].upper() + + +def get_region_friendly_name(region_name, friendly_names=None): + """ + Get a friendly display name for a region. + + Region friendly names are loaded from region_friendly_names.yml. + If a region is not found in the YAML file, an auto-generated name + is returned. + + The YAML file can be updated to add new regions or customize names. + See load_region_friendly_names() for update instructions. + + Args: + region_name (str): OCI region name (e.g., 'us-chicago-1') + friendly_names (dict): Optional pre-loaded friendly names dict. + If None, names will be loaded from YAML. + + Returns: + str: Friendly name (e.g., 'US Midwest (Chicago)') + """ + # Load friendly names from YAML if not provided + if friendly_names is None: + friendly_names = load_region_friendly_names() + + # Look up the friendly name in the loaded data + if region_name in friendly_names: + return friendly_names[region_name] + + # Auto-generate if not in map + parts = region_name.split("-") + if len(parts) >= 2: + location = parts[1].title() + return f"{parts[0].upper()} ({location})" + return region_name + + +def get_all_regions(): + """ + Retrieve the list of all OCI regions in the OC1 realm. + + Returns all regions available in OCI and marks which ones the tenancy + is subscribed to, making the subscription status field meaningful. + + Returns: + list: sorted list of dictionaries each containing a region + """ + try: + config = get_oci_config() + identity = create_identity_client() + + # Get all regions in the OC1 realm + all_regions = identity.list_regions().data + + # Get region subscriptions to determine which regions are subscribed + region_subscriptions = identity.list_region_subscriptions( + config["tenancy"] + ).data + + # Create a mapping of subscribed regions for quick lookup + subscribed_regions = {} + home_region = None + for subscription in region_subscriptions: + subscribed_regions[subscription.region_name] = subscription.status + if subscription.is_home_region: + home_region = subscription.region_name + + # Load friendly names once for efficiency + friendly_names = load_region_friendly_names() + + regions = [] + for region in all_regions: + region_name = region.name + is_subscribed = region_name in subscribed_regions + regions.append( + { + "region_name": region_name, + "region_code": region.key, + "friendly_name": get_region_friendly_name( + region_name, friendly_names + ), + "status": subscribed_regions.get(region_name, "NOT_SUBSCRIBED"), + "is_home_region": region_name == home_region, + "is_subscribed": is_subscribed, + } + ) + + return sorted(regions, key=lambda x: x["region_name"]) + + except oci.exceptions.ConfigFileNotFound: + print( + "Error: OCI config file not found. Please configure OCI CLI.", + file=sys.stderr, + ) + return [] + except Exception as e: + print(f"Error retrieving OCI regions: {e}", file=sys.stderr) + return [] + + +def get_region_info(regions, region_name, quiet=False): + """ + Get detailed information about a specific region including availability domains. + + Args: + regions (list): List of all regions + region_name (str): OCI region name (e.g., 'us-chicago-1') + quiet (bool): Suppress debug messages + + Returns: + dict: Dictionary containing region information and availability domains + """ + try: + if not quiet: + print(f"Querying information for region {region_name}...", file=sys.stderr) + + region_info = next( + filter(lambda x: x["region_name"] == region_name, regions), None + ) + if not region_info: + if not quiet: + print(f"Region {region_name} was not found", file=sys.stderr) + return None + + # Create identity client for the specific region + identity = create_identity_client(region_name) + config = get_oci_config(region_name) + + # List availability domains + availability_domains = identity.list_availability_domains( + config["tenancy"] + ).data + + ad_list = [] + for ad in availability_domains: + # Extract AD number from name (e.g., "MhqG:US-CHICAGO-1-AD-1" -> 1) + ad_name = ad.name + ad_number = ad_name.split("-")[-1] if "-" in ad_name else "1" + + ad_info = { + "name": ad_name, + "number": ad_number, + } + ad_list.append(ad_info) + + result = { + "region_name": region_info["region_name"], + "region_code": region_info["region_code"], + "friendly_name": region_info["friendly_name"], + "status": region_info.get("status", "READY"), + "is_home_region": region_info.get("is_home_region", False), + "availability_domain_count": len(ad_list), + "availability_domains": sorted(ad_list, key=lambda x: x["number"]), + } + + if not quiet: + print( + f"Found {len(ad_list)} availability domains in {region_name}", + file=sys.stderr, + ) + + return result + + except ServiceError as e: + print(f"OCI API Error: {e.message}", file=sys.stderr) + return None + except Exception as e: + print(f"Unexpected error: {e}", file=sys.stderr) + return None + + +def output_region_kconfig(region_info): + """Output region information in Kconfig format.""" + environment = get_jinja2_environment() + template = environment.get_template("ad.j2") + print( + template.render( + region_code=region_info["region_code"], + region_name=region_info["region_name"], + ads=region_info["availability_domains"], + ) + ) + + +def output_region_raw(region_info, quiet=False): + """Output region information in table format.""" + if not quiet: + print(f"Region: {region_info['region_name']}") + print(f"Code: {region_info['region_code']}") + print(f"Friendly Name: {region_info['friendly_name']}") + print(f"Status: {region_info['status']}") + print(f"Home Region: {region_info['is_home_region']}") + print(f"Availability Domains: {region_info['availability_domain_count']}") + + print(f"{'AD Name':<40} {'AD Number':<10}") + print("-" * 50) + + for ad in region_info["availability_domains"]: + print(f"{ad['name']:<40} {ad['number']:<10}") + + +def output_regions_kconfig(regions): + """Output available regions in kconfig format.""" + environment = get_jinja2_environment() + template = environment.get_template("regions.j2") + print( + template.render( + default_region=get_region_code(regions, get_default_region()), + regions=regions, + ) + ) + + +def output_regions_raw(regions, quiet=False): + """Output available regions in table format.""" + if not quiet: + print(f"Available OCI regions ({len(regions)}):\n") + print(f"{'Region Name':<20} {'Code':<8} {'Status':<12} {'Home':<8}") + print("-" * 50) + + for region in regions: + status = region.get("status", "Unknown") + is_home = "Yes" if region.get("is_home_region", False) else "No" + print( + f"{region['region_name']:<20} {region['region_code']:<8} {status:<12} {is_home:<8}" + ) + + +def output_locations_kconfig(regions, include_unsubscribed=False): + """ + Output the complete locations menu in Kconfig format. + + Args: + regions (list): List of all regions + include_unsubscribed (bool): Include non-subscribed regions in output + """ + environment = get_jinja2_environment() + + # Filter to subscribed regions only unless --include-unsubscribed is specified + # (can't deploy to non-subscribed regions, so they shouldn't be in Kconfig by default) + if include_unsubscribed: + kconfig_regions = regions + else: + kconfig_regions = [r for r in regions if r.get("is_subscribed", False)] + + # Output the region choice menu + template = environment.get_template("regions.j2") + print( + template.render( + default_region=get_region_code(kconfig_regions, get_default_region()), + regions=kconfig_regions, + ) + ) + + # Output each region's availability domain configuration + # Note: Can only query AD info for subscribed regions + template = environment.get_template("ad.j2") + for region in kconfig_regions: + # For non-subscribed regions, create a default AD configuration + # (API will fail with auth error for non-subscribed regions) + if not region.get("is_subscribed", True): + # Default to 1 availability domain for unsubscribed regions + region_info = { + "region_name": region["region_name"], + "region_code": region["region_code"], + "friendly_name": region["friendly_name"], + "status": region.get("status", "NOT_SUBSCRIBED"), + "is_home_region": False, + "availability_domain_count": 1, + "availability_domains": [ + { + "name": f"{region['region_name'].upper()}-AD-1", + "number": "1", + } + ], + } + else: + region_info = get_region_info(kconfig_regions, region["region_name"], True) + + if region_info: + print() + print( + template.render( + region_code=region_info["region_code"], + region_name=region_info["region_name"], + ads=region_info["availability_domains"], + ) + ) + + # Output the compartment name configuration + print() + print("config TERRAFORM_OCI_COMPARTMENT_NAME") + print('\tstring "OCI compartment name"') + print("\toutput yaml") + print("\thelp") + print("\t The compartment name where your instances are to be created.") + + +def parse_arguments(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Get OCI region and availability domain information", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python %(prog)s --regions + python %(prog)s us-chicago-1 + python %(prog)s ap-mumbai-1 --quiet + python %(prog)s --include-unsubscribed > kconfigs/Kconfig.location + """, + ) + parser.add_argument( + "region_name", + nargs="?", + help="OCI region name (e.g., us-chicago-1, ap-mumbai-1)", + ) + + parser.add_argument( + "--format", + "-f", + choices=["raw", "kconfig"], + default="kconfig", + help="Output format (default: kconfig)", + ) + parser.add_argument( + "--quiet", "-q", action="store_true", help="Suppress informational messages" + ) + parser.add_argument( + "--regions", action="store_true", help="List all available OCI regions" + ) + parser.add_argument( + "--include-unsubscribed", + action="store_true", + help="Include non-subscribed regions in Kconfig output (default: subscribed only)", + ) + return parser.parse_args() + + +def main(): + """Main function to run the program.""" + args = parse_arguments() + + if not args.quiet: + print("Fetching list of OCI region subscriptions...", file=sys.stderr) + regions = get_all_regions() + if not regions: + sys.exit(1) + + if args.regions: + if args.format == "kconfig": + output_regions_kconfig(regions) + else: + output_regions_raw(regions, args.quiet) + return + + if args.region_name: + if not args.quiet: + print( + f"Fetching information for region {args.region_name}...", + file=sys.stderr, + ) + + region_info = get_region_info(regions, args.region_name, args.quiet) + if region_info: + if args.format == "kconfig": + output_region_kconfig(region_info) + else: + output_region_raw(region_info, args.quiet) + else: + print( + f"Could not retrieve information for region '{args.region_name}'.", + file=sys.stderr, + ) + print( + "Try running with --regions to see available regions.", file=sys.stderr + ) + sys.exit(1) + return + + output_locations_kconfig(regions, args.include_unsubscribed) + + +if __name__ == "__main__": + main() diff --git a/terraform/oci/scripts/gen_kconfig_shape b/terraform/oci/scripts/gen_kconfig_shape new file mode 100755 index 000000000..09dd6d6fe --- /dev/null +++ b/terraform/oci/scripts/gen_kconfig_shape @@ -0,0 +1,950 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +""" +Retrieve compute shape information from OCI. Use it to construct the "shapes" +Kconfig menu. + +OCI shapes represent compute instance configurations with varying combinations +of CPU, memory, storage, and networking capacity. This script queries the OCI +API to discover available shapes and generates Kconfig menu entries for them. + +Shape Discovery: + By default, this script aggregates shapes from all subscribed regions to + provide a comprehensive list of shapes actually available in your tenancy. + + The --include-catalog option adds well-known shapes (like DenseIO, GPU shapes) + that may require service limit increases or are in limited availability. + +Usage: + # Generate shapes Kconfig from all subscribed regions (default) + ./gen_kconfig_shape > ../kconfigs/Kconfig.shapes + + # Include catalog shapes that may need service limits + ./gen_kconfig_shape --include-catalog > ../kconfigs/Kconfig.shapes + + # List all available shape families + ./gen_kconfig_shape --families + + # Get details for a specific shape family + ./gen_kconfig_shape VM.Standard.E4 +""" + +import sys +import os +import argparse + +import oci +from oci.exceptions import ServiceError, ConfigFileNotFound + +from oci_common import ( + get_default_region, + get_default_compartment, + get_subscribed_regions, + get_jinja2_environment, + load_yaml_config, + create_compute_client, +) + + +def get_all_shapes(compartment_ocid, regions=None, quiet=False): + """ + Get all available compute shapes across specified regions. + + Args: + compartment_ocid (str): OCI compartment OCID + regions (list): List of region names to query. If None, uses default region. + quiet (bool): Suppress debug messages + + Returns: + list: List of shape objects aggregated from all regions (deduplicated by name) + """ + if regions is None: + regions = [get_default_region()] + + all_shapes = {} # Use dict to deduplicate by shape name + + for region in regions: + if not quiet: + print(f"Fetching shapes from {region}...", file=sys.stderr) + + try: + compute = create_compute_client(region) + + shapes_response = compute.list_shapes(compartment_ocid) + shapes = shapes_response.data + + # Add shapes to dict, using shape name as key to deduplicate + for shape in shapes: + if shape.shape not in all_shapes: + all_shapes[shape.shape] = shape + + if not quiet: + print(f" Found {len(shapes)} shapes in {region}", file=sys.stderr) + + except ConfigFileNotFound: + print( + "Error: OCI config file not found. Please configure OCI CLI.", + file=sys.stderr, + ) + return [] + except ServiceError as e: + print(f" Warning: Could not query {region}: {e.message}", file=sys.stderr) + continue + except Exception as e: + print(f" Warning: Error querying {region}: {e}", file=sys.stderr) + continue + + if not quiet: + print( + f"\nTotal unique shapes across all regions: {len(all_shapes)}", + file=sys.stderr, + ) + + return list(all_shapes.values()) + + +def get_catalog_shapes(): + """ + Return a list of well-known OCI shapes that may not be visible via API. + + These shapes may require service limit increases or are in limited + availability. They are included to provide a complete menu of shapes + that users can request access to. + + The catalog is loaded from catalog_shapes.yml to make it easier to + update when Oracle adds new shapes. See catalog_shapes.yml for + instructions on how to update the catalog. + + Returns: + dict: Dictionary mapping shape names to their basic properties + """ + return load_yaml_config("catalog_shapes.yml") + + +def merge_catalog_shapes(api_shapes, quiet=False): + """ + Merge API-discovered shapes with catalog shapes. + + Args: + api_shapes (list): Shapes discovered via API + quiet (bool): Suppress debug messages + + Returns: + list: Combined list of API shapes plus catalog shapes (deduplicated) + """ + # Create a dict from API shapes + shapes_dict = {shape.shape: shape for shape in api_shapes} + + catalog = get_catalog_shapes() + added_count = 0 + + # Mark all API shapes as not from catalog + for shape in shapes_dict.values(): + shape.is_catalog_shape = False + + # Add catalog shapes that aren't already in API results + for shape_name, properties in catalog.items(): + if shape_name not in shapes_dict: + # Create a minimal shape object with catalog properties + # We'll use a simple namespace object to mimic OCI shape structure + from types import SimpleNamespace + + catalog_shape = SimpleNamespace( + shape=shape_name, + processor_description=properties.get("description", ""), + memory_in_gbs=0, # Will show as "Flexible" or unknown + ocpus=0, # Will show as "Flexible" or unknown + gpus=1 if properties.get("has_gpu", False) else 0, + is_catalog_shape=True, # Mark as catalog shape + ) + shapes_dict[shape_name] = catalog_shape + added_count += 1 + + if not quiet and added_count > 0: + print(f"Added {added_count} shapes from catalog", file=sys.stderr) + + return list(shapes_dict.values()) + + +def parse_all_shape_families(shapes, quiet=False): + """ + Extract shape families from the list of shapes. + + OCI shape names follow a pattern like "VM.Standard.E4.Flex" or + "BM.Standard2.52". This function groups shapes by their family + prefix (e.g., "VM.Standard.E4" or "BM.Standard2"). + + Args: + shapes (list): List of shape objects from OCI API + quiet (bool): Suppress debug messages + + Returns: + dict: Dictionary with family info including count of shapes per family + """ + families = {} + seen_shapes = set() + + for shape in shapes: + shape_name = shape.shape + + # Skip duplicate shape names + if shape_name in seen_shapes: + continue + seen_shapes.add(shape_name) + + # Parse shape family from name + # Examples: + # VM.Standard.E4.Flex -> VM.Standard.E4 + # VM.Standard3.Flex -> VM.Standard3 + # BM.Standard2.52 -> BM.Standard2 + parts = shape_name.split(".") + + # Determine family based on shape naming patterns + if len(parts) >= 3: + # Handle patterns like VM.Standard.E4.Flex or VM.Standard.A1.Flex + if parts[-1] == "Flex": + family = ".".join(parts[:-1]) # VM.Standard.E4 + else: + # Handle fixed shapes like BM.Standard2.52 + family = ".".join(parts[:-1]) # BM.Standard2 + elif len(parts) == 2: + # Handle patterns like VM.Standard3.Flex -> VM.Standard3 + family = ".".join(parts) + else: + family = shape_name + + if family not in families: + families[family] = { + "family_name": family, + "shape_count": 0, + "has_gpu": False, + "architectures": set(), + "is_flex": False, + "is_bare_metal": False, + "has_catalog_shapes": False, + } + + families[family]["shape_count"] += 1 + + # Determine if it's a flex shape + if ".Flex" in shape_name or shape_name.endswith(".Flex"): + families[family]["is_flex"] = True + + # Determine if it's bare metal + if shape_name.startswith("BM."): + families[family]["is_bare_metal"] = True + + # Check for GPU + if hasattr(shape, "gpus") and shape.gpus > 0: + families[family]["has_gpu"] = True + + # Check if this shape is from catalog + if getattr(shape, "is_catalog_shape", False): + families[family]["has_catalog_shapes"] = True + + # Get processor architecture + if hasattr(shape, "processor_description"): + proc_desc = shape.processor_description.lower() + if "amd" in proc_desc or "intel" in proc_desc or "x86" in proc_desc: + families[family]["architectures"].add("x86_64") + elif "arm" in proc_desc or "ampere" in proc_desc: + families[family]["architectures"].add("arm64") + else: + families[family]["architectures"].add("x86_64") # Default to x86_64 + else: + # Default architecture based on shape naming + if "A1" in shape_name or "A2" in shape_name: + families[family]["architectures"].add("arm64") + else: + families[family]["architectures"].add("x86_64") + + # Convert architecture sets to sorted lists for JSON serialization + for family in families.values(): + family["architectures"] = sorted(list(family["architectures"])) + + return families + + +def get_gpu_info(shape): + """ + Extract GPU information from shape data. + + Args: + shape: Shape object from OCI API + + Returns: + str: Formatted GPU information string + """ + if not hasattr(shape, "gpus") or shape.gpus == 0: + return "None" + + gpu_count = shape.gpus + + # Try to get GPU description if available + gpu_desc = getattr(shape, "gpu_description", None) + if gpu_desc: + if gpu_count > 1: + return f"{gpu_count}x {gpu_desc}" + return gpu_desc + + # Fallback to just count + if gpu_count > 1: + return f"{gpu_count}x GPU" + return "GPU" + + +def extract_cpu_architecture(shape): + """ + Determine CPU architecture from shape information. + + Args: + shape: Shape object from OCI API + + Returns: + str: CPU architecture ('arm64' or 'x86_64') + """ + shape_name = shape.shape + cpu_isa = "x86_64" # Default + + # Check processor description + if hasattr(shape, "processor_description"): + proc_desc = shape.processor_description.lower() + if "arm" in proc_desc or "ampere" in proc_desc: + return "arm64" + elif "amd" in proc_desc or "intel" in proc_desc: + return "x86_64" + + # Fall back to shape naming patterns + if "A1" in shape_name or "A2" in shape_name: + return "arm64" + + return cpu_isa + + +def extract_memory_info(shape): + """ + Extract memory information from shape data. + + Args: + shape: Shape object from OCI API + + Returns: + dict: Dictionary with memory_gb and optional flex memory ranges + """ + memory_info = { + "memory_gb": 0, + } + + if hasattr(shape, "memory_in_gbs"): + memory_info["memory_gb"] = shape.memory_in_gbs + elif hasattr(shape, "memory_options"): + # Flex shapes have memory options + if hasattr(shape.memory_options, "default_per_ocpu_in_g_bs"): + # For flex shapes, use a default OCPU count to show typical memory + default_ocpus = 1 + if hasattr(shape, "ocpus"): + default_ocpus = shape.ocpus + memory_info["memory_gb"] = ( + shape.memory_options.default_per_ocpu_in_g_bs * default_ocpus + ) + + # Extract min/max memory per OCPU for flex shapes + if hasattr(shape.memory_options, "min_per_ocpu_in_g_bs"): + memory_info["memory_per_ocpu_min"] = ( + shape.memory_options.min_per_ocpu_in_g_bs + ) + if hasattr(shape.memory_options, "max_per_ocpu_in_g_bs"): + memory_info["memory_per_ocpu_max"] = ( + shape.memory_options.max_per_ocpu_in_g_bs + ) + if hasattr(shape.memory_options, "min_in_g_bs"): + memory_info["memory_min"] = shape.memory_options.min_in_g_bs + if hasattr(shape.memory_options, "max_in_g_bs"): + memory_info["memory_max"] = shape.memory_options.max_in_g_bs + + return memory_info + + +def extract_ocpu_info(shape): + """ + Extract OCPU information from shape data. + + Args: + shape: Shape object from OCI API + + Returns: + dict: Dictionary with ocpus and optional flex OCPU ranges + """ + ocpu_info = { + "ocpus": 0, + } + + if hasattr(shape, "ocpus"): + ocpu_info["ocpus"] = shape.ocpus + elif hasattr(shape, "ocpu_options"): + # Flex shapes have OCPU options + if hasattr(shape.ocpu_options, "min"): + ocpu_info["ocpus"] = shape.ocpu_options.min + ocpu_info["ocpu_min"] = shape.ocpu_options.min + if hasattr(shape.ocpu_options, "max"): + ocpu_info["ocpu_max"] = shape.ocpu_options.max + + return ocpu_info + + +def extract_network_info(shape): + """ + Extract network bandwidth information from shape data. + + Args: + shape: Shape object from OCI API + + Returns: + str: Network bandwidth description + """ + if hasattr(shape, "networking_bandwidth_in_gbps"): + return f"{shape.networking_bandwidth_in_gbps} Gbps" + elif hasattr(shape, "max_vnic_attachments"): + return f"{shape.max_vnic_attachments} VNICs" + return "Not specified" + + +def extract_storage_info(shape): + """ + Extract storage information from shape data. + + Args: + shape: Shape object from OCI API + + Returns: + str: Storage description + """ + if hasattr(shape, "local_disks") and shape.local_disks > 0: + disk_size = getattr(shape, "local_disks_total_size_in_gbs", 0) + return f"{disk_size} GB local storage ({shape.local_disks} disks)" + return "Block storage only" + + +def extract_shape_info(shape): + """ + Extract detailed information from a single shape object. + + Args: + shape: Shape object from OCI API + + Returns: + dict: Dictionary containing shape information + """ + shape_name = shape.shape + + # Extract various aspects of the shape + cpu_isa = extract_cpu_architecture(shape) + gpu_info = get_gpu_info(shape) + memory_info = extract_memory_info(shape) + ocpu_info = extract_ocpu_info(shape) + network_bandwidth = extract_network_info(shape) + storage = extract_storage_info(shape) + + # Build the hardware info dictionary + hardware_info = { + "shape_name": shape_name, + "ocpus": ocpu_info["ocpus"] if ocpu_info["ocpus"] > 0 else "Flexible", + "memory_gb": memory_info["memory_gb"] + if memory_info["memory_gb"] > 0 + else "Flexible", + "cpu_isa": cpu_isa, + "gpu": gpu_info, + "network_performance": network_bandwidth, + "storage": storage, + "is_flex": ".Flex" in shape_name or shape_name.endswith(".Flex"), + "is_bare_metal": shape_name.startswith("BM."), + "is_catalog_shape": getattr(shape, "is_catalog_shape", False), + } + + # Add flex shape ranges if available + for key in ["ocpu_min", "ocpu_max"]: + if key in ocpu_info: + hardware_info[key] = ocpu_info[key] + + for key in [ + "memory_min", + "memory_max", + "memory_per_ocpu_min", + "memory_per_ocpu_max", + ]: + if key in memory_info: + hardware_info[key] = memory_info[key] + + # Add processor description if available + if hasattr(shape, "processor_description"): + hardware_info["processor"] = shape.processor_description + + return hardware_info + + +def get_shape_family_info(family_name, shapes, region, quiet=False): + """ + Get shape information for a specific OCI shape family. + + Args: + family_name (str): Shape family name (e.g., 'VM.Standard.E4', 'BM.Standard2') + shapes (list): List of all shapes + region (str): OCI region being queried + quiet (bool): Suppress debug messages + + Returns: + list: List of dictionaries containing shape information + """ + family_shapes = [] + + for shape in shapes: + shape_name = shape.shape + + # Match shapes that belong to this family + if shape_name.startswith(family_name): + family_shapes.append(shape) + + if not family_shapes: + if not quiet: + print(f"No shapes found starting with '{family_name}'.", file=sys.stderr) + return [] + + if not quiet: + print( + f"Found {len(family_shapes)} shapes in family '{family_name}'", + file=sys.stderr, + ) + + shape_info = [] + seen_shapes = set() + + for shape in family_shapes: + shape_name = shape.shape + + # Skip duplicate shape names (OCI API may return same shape multiple times) + if shape_name in seen_shapes: + continue + seen_shapes.add(shape_name) + + # Get processor architecture + cpu_isa = "x86_64" # Default + if hasattr(shape, "processor_description"): + proc_desc = shape.processor_description.lower() + if "arm" in proc_desc or "ampere" in proc_desc: + cpu_isa = "arm64" + elif "amd" in proc_desc or "intel" in proc_desc: + cpu_isa = "x86_64" + + # Shape naming patterns for ARM detection + if "A1" in shape_name or "A2" in shape_name: + cpu_isa = "arm64" + + gpu_info = get_gpu_info(shape) + + # Get memory in GB + memory_gb = 0 + memory_min = None + memory_max = None + memory_per_ocpu_min = None + memory_per_ocpu_max = None + if hasattr(shape, "memory_in_gbs"): + memory_gb = shape.memory_in_gbs + elif hasattr(shape, "memory_options"): + # Flex shapes have memory options + if hasattr(shape.memory_options, "default_per_ocpu_in_g_bs"): + # For flex shapes, use a default OCPU count to show typical memory + default_ocpus = 1 + if hasattr(shape, "ocpus"): + default_ocpus = shape.ocpus + memory_gb = ( + shape.memory_options.default_per_ocpu_in_g_bs * default_ocpus + ) + # Extract min/max memory per OCPU for flex shapes + if hasattr(shape.memory_options, "min_per_ocpu_in_g_bs"): + memory_per_ocpu_min = shape.memory_options.min_per_ocpu_in_g_bs + if hasattr(shape.memory_options, "max_per_ocpu_in_g_bs"): + memory_per_ocpu_max = shape.memory_options.max_per_ocpu_in_g_bs + if hasattr(shape.memory_options, "min_in_g_bs"): + memory_min = shape.memory_options.min_in_g_bs + if hasattr(shape.memory_options, "max_in_g_bs"): + memory_max = shape.memory_options.max_in_g_bs + + # Get OCPU count + ocpus = 0 + ocpu_min = None + ocpu_max = None + if hasattr(shape, "ocpus"): + ocpus = shape.ocpus + elif hasattr(shape, "ocpu_options"): + # Flex shapes have OCPU options + if hasattr(shape.ocpu_options, "min"): + ocpus = shape.ocpu_options.min + ocpu_min = shape.ocpu_options.min + if hasattr(shape.ocpu_options, "max"): + ocpu_max = shape.ocpu_options.max + + # Network bandwidth + network_bandwidth = "Not specified" + if hasattr(shape, "networking_bandwidth_in_gbps"): + network_bandwidth = f"{shape.networking_bandwidth_in_gbps} Gbps" + elif hasattr(shape, "max_vnic_attachments"): + network_bandwidth = f"{shape.max_vnic_attachments} VNICs" + + # Storage + storage = "Block storage only" + if hasattr(shape, "local_disks") and shape.local_disks > 0: + disk_size = getattr(shape, "local_disks_total_size_in_gbs", 0) + storage = f"{disk_size} GB local storage ({shape.local_disks} disks)" + + hardware_info = { + "shape_name": shape_name, + "ocpus": ocpus if ocpus > 0 else "Flexible", + "memory_gb": memory_gb if memory_gb > 0 else "Flexible", + "cpu_isa": cpu_isa, + "gpu": gpu_info, + "network_performance": network_bandwidth, + "storage": storage, + "is_flex": ".Flex" in shape_name or shape_name.endswith(".Flex"), + "is_bare_metal": shape_name.startswith("BM."), + "is_catalog_shape": getattr(shape, "is_catalog_shape", False), + } + + # Add flex shape ranges if available + if ocpu_min is not None: + hardware_info["ocpu_min"] = ocpu_min + if ocpu_max is not None: + hardware_info["ocpu_max"] = ocpu_max + if memory_min is not None: + hardware_info["memory_min"] = memory_min + if memory_max is not None: + hardware_info["memory_max"] = memory_max + if memory_per_ocpu_min is not None: + hardware_info["memory_per_ocpu_min"] = memory_per_ocpu_min + if memory_per_ocpu_max is not None: + hardware_info["memory_per_ocpu_max"] = memory_per_ocpu_max + + # Add processor description if available + if hasattr(shape, "processor_description"): + hardware_info["processor"] = shape.processor_description + + shape_info.append(hardware_info) + + # Sort by memory size (handling 'Flexible' string) + def sort_key(x): + mem = x["memory_gb"] + return (0, 0) if mem == "Flexible" else (1, float(mem)) + + return sorted(shape_info, key=sort_key) + + +def group_shapes_by_type(shapes, region): + """ + Group shapes by type (flex, fixed, bare_metal). + + Args: + shapes (list): List of all shapes + region (str): OCI region being queried + + Returns: + dict: Dictionary with 'flex', 'fixed', and 'bare_metal' keys containing shape lists + """ + flex_shapes = [] + fixed_shapes = [] + bare_metal_shapes = [] + seen_shapes = set() + + for shape in shapes: + shape_name = shape.shape + + # Skip duplicate shape names + if shape_name in seen_shapes: + continue + seen_shapes.add(shape_name) + + # Extract shape information directly (O(1) operation per shape) + info = extract_shape_info(shape) + + # Categorize by type + if info["is_flex"]: + flex_shapes.append(info) + elif info["is_bare_metal"]: + bare_metal_shapes.append(info) + else: + # Fixed shapes: VM shapes that are not flex + if shape_name.startswith("VM."): + fixed_shapes.append(info) + + # Sort shapes within each category + def sort_key(x): + # Sort by shape name + return x["shape_name"] + + flex_shapes.sort(key=sort_key) + fixed_shapes.sort(key=sort_key) + bare_metal_shapes.sort(key=sort_key) + + return { + "flex": flex_shapes, + "fixed": fixed_shapes, + "bare_metal": bare_metal_shapes, + } + + +def output_shapes_kconfig(shapes, region): + """Output shapes menu in Kconfig format.""" + environment = get_jinja2_environment() + + # Output the top-level choice menu (GENERIC, FLEX, FIXED, BARE_METAL) + template = environment.get_template("shape_families.j2") + print(template.render()) + print() + + # Output the GENERIC family submenu + template = environment.get_template("generic_family.j2") + print(template.render()) + print() + + # Group shapes by type + shape_groups = group_shapes_by_type(shapes, region) + + # Output FLEX shapes submenu + if shape_groups["flex"]: + template = environment.get_template("flex_shapes.j2") + print(template.render(shapes=shape_groups["flex"])) + print() + + # Output FIXED shapes submenu + if shape_groups["fixed"]: + template = environment.get_template("fixed_shapes.j2") + print(template.render(shapes=shape_groups["fixed"])) + print() + + # Output BARE_METAL shapes submenu + if shape_groups["bare_metal"]: + template = environment.get_template("bare_metal_shapes.j2") + print(template.render(shapes=shape_groups["bare_metal"])) + print() + + +def output_families_kconfig(shapes): + """Output shape families in Kconfig format.""" + families = parse_all_shape_families(shapes) + sorted_families = sorted(families.values(), key=lambda x: x["family_name"]) + + environment = get_jinja2_environment() + + template = environment.get_template("shape_families.j2") + print( + template.render( + sorted_families=sorted_families, + ) + ) + + +def output_families_raw(shapes, region, quiet=False): + """Output available shape families in table format.""" + families = parse_all_shape_families(shapes) + + if not quiet: + print(f"Available shape families in {region}:\n") + + print(f"{'Family':<25} {'Count':<6} {'GPU':<5} {'Type':<12} {'Architectures':<20}") + print("-" * 75) + + sorted_families = sorted(families.values(), key=lambda x: x["family_name"]) + has_any_catalog = False + for family in sorted_families: + gpu_indicator = "Yes" if family["has_gpu"] else "No" + architectures = ", ".join(family["architectures"]) + + shape_type = [] + if family["is_flex"]: + shape_type.append("Flex") + if family["is_bare_metal"]: + shape_type.append("Bare Metal") + if not shape_type: + shape_type.append("Fixed") + shape_type_str = ", ".join(shape_type) + + family_name = family["family_name"] + if family.get("has_catalog_shapes", False): + family_name = family_name + " *" + has_any_catalog = True + + print( + f"{family_name:<25} " + f"{family['shape_count']:<6} " + f"{gpu_indicator:<5} " + f"{shape_type_str:<12} " + f"{architectures:<20}" + ) + + if has_any_catalog: + print("\n* Contains catalog shapes - may require service limit increases") + + if not quiet: + print(f"\nFound {len(families)} shape families", file=sys.stderr) + + +def output_family_kconfig(family_name, shapes): + """Output results in kconfig format.""" + environment = get_jinja2_environment() + template = environment.get_template("shape_family.j2") + print( + template.render( + family_name=family_name.upper().replace(".", "_").replace("-", "_"), + shapes=shapes, + ) + ) + + +def output_family_raw(shapes, quiet=False): + """Output results in table format.""" + if not quiet: + print(f"Found {len(shapes)} shapes:\n") + + print( + f"{'Shape Name':<30} {'OCPUs':<10} {'Memory (GB)':<15} {'CPU ISA':<10} {'GPU':<25} {'Storage':<30}" + ) + print("-" * 130) + + for shape in shapes: + shape_name = shape["shape_name"] + if shape.get("is_catalog_shape", False): + shape_name = shape_name + " *" + print( + f"{shape_name:<30} " + f"{str(shape['ocpus']):<10} " + f"{str(shape['memory_gb']):<15} " + f"{shape['cpu_isa']:<10} " + f"{shape['gpu']:<25} " + f"{shape['storage']:<30}" + ) + + # Add note about catalog shapes if any are present + has_catalog = any(shape.get("is_catalog_shape", False) for shape in shapes) + if has_catalog: + print("\n* Catalog shape - may require service limit increases") + + +def parse_arguments(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Get OCI compute shape information including hardware specs", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Generate Kconfig from all subscribed regions (default) + python %(prog)s > ../kconfigs/Kconfig.shapes + + # Include catalog shapes (DenseIO, GPU, etc.) + python %(prog)s --include-catalog > ../kconfigs/Kconfig.shapes + + # Query specific shape family + python %(prog)s VM.Standard.E4 + + # List all available families + python %(prog)s --families --format raw + + # Query specific region only + python %(prog)s --region us-chicago-1 --families + """, + ) + parser.add_argument( + "family_name", + nargs="?", # Make family_name optional when using --families + help="Shape family name (e.g., VM.Standard.E4, VM.Standard3, BM.Standard2)", + ) + + parser.add_argument( + "--families", action="store_true", help="List all available shape families" + ) + parser.add_argument( + "--include-catalog", + action="store_true", + help="Include well-known shapes from catalog (DenseIO, GPU shapes) that may require service limits", + ) + parser.add_argument( + "--format", + "-f", + choices=["raw", "kconfig"], + default="kconfig", + help="Output format (default: kconfig)", + ) + parser.add_argument( + "--quiet", "-q", action="store_true", help="Suppress informational messages" + ) + parser.add_argument( + "--region", + "-r", + help="Query specific region only (default: aggregate from all subscribed regions)", + ) + return parser.parse_args() + + +def main(): + """Main function to run the program.""" + args = parse_arguments() + + compartment_ocid = get_default_compartment() + if not compartment_ocid: + print("Error: Could not determine compartment OCID", file=sys.stderr) + sys.exit(1) + + # Determine which regions to query + if args.region: + # Query specific region only + regions = [args.region] + region_desc = args.region + else: + # Query all subscribed regions (default) + regions = get_subscribed_regions(args.quiet) + region_desc = "all subscribed regions" + + # Get shapes from OCI API + shapes = get_all_shapes(compartment_ocid, regions, args.quiet) + if not shapes: + sys.exit(1) + + # Optionally merge with catalog shapes + if args.include_catalog: + shapes = merge_catalog_shapes(shapes, args.quiet) + + if args.families: + if args.format == "kconfig": + output_families_kconfig(shapes) + else: + output_families_raw(shapes, region_desc, args.quiet) + return + + if args.family_name: + if not args.quiet: + print( + f"Fetching information for the {args.family_name} family...", + file=sys.stderr, + ) + + family_shapes = get_shape_family_info( + args.family_name, shapes, region_desc, args.quiet + ) + + if not family_shapes: + print(f"No shapes found for family '{args.family_name}'.", file=sys.stderr) + print( + "Try running with --families to see available shape families.", + file=sys.stderr, + ) + sys.exit(1) + + if args.format == "kconfig": + output_family_kconfig(args.family_name, family_shapes) + else: + output_family_raw(family_shapes, args.quiet) + return + + output_shapes_kconfig(shapes, region_desc) + + +if __name__ == "__main__": + main() diff --git a/terraform/oci/kconfigs/shapes/Kconfig.generic b/terraform/oci/scripts/generic_family.j2 similarity index 81% rename from terraform/oci/kconfigs/shapes/Kconfig.generic rename to terraform/oci/scripts/generic_family.j2 index b6893a97c..0833f75eb 100644 --- a/terraform/oci/kconfigs/shapes/Kconfig.generic +++ b/terraform/oci/scripts/generic_family.j2 @@ -10,6 +10,9 @@ choice config TERRAFORM_OCI_SHAPE_VM_STANDARD_X86_GENERIC bool "VM.Standard.x86.Generic" depends on TARGET_ARCH_X86_64 + help + Generic x86 shape that lets you customize CPU and memory + without choosing a specific CPU generation. endchoice @@ -23,14 +26,14 @@ config TERRAFORM_OCI_INSTANCE_FLEX_OCPUS output yaml default 2 help - The Oracle CPU (OCPU) represents physical CPU cores and is + An Oracle CPU (OCPU) represents a physical CPU core and is the unit of measurement for CPUs on x86 CPUs (AMD and Intel) and Arm CPUs (OCI Ampere Compute). A virtual CPU (vCPU), the industry-standard for measuring compute resources, represents one execution thread of a physical CPU core. - Most CPU architectures, including x86, runs two threads + Most CPU architectures, including x86, run two threads per physical core, so one OCPU is the equal of two vCPUs for x86-based compute. For OCI Compute, the minimum unit of provisioning starts from one OCPU on both X86 (Intel @@ -42,7 +45,7 @@ config TERRAFORM_OCI_INSTANCE_FLEX_MEMORY_IN_GBS default 4 help Memory per instance, in GiBs. The minimum value for this - setting is a multiple of the number of OCPUS in each + setting is a multiple of the number of OCPUs in each instance. endif # TERRAFORM_OCI_SHAPE_FAMILY_GENERIC diff --git a/terraform/oci/scripts/image_distributions.j2 b/terraform/oci/scripts/image_distributions.j2 new file mode 100644 index 000000000..ecfa38eb6 --- /dev/null +++ b/terraform/oci/scripts/image_distributions.j2 @@ -0,0 +1,90 @@ +choice + prompt "Distribution" +{% if 'oracle' in publishers %} + default TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX +{% elif 'ubuntu' in publishers %} + default TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU +{% elif 'centos' in publishers %} + default TERRAFORM_OCI_OPERATING_SYSTEM_CENTOS +{% elif publishers %} + default TERRAFORM_OCI_OPERATING_SYSTEM_{{ publishers[0] | upper }} +{% endif %} + help + Select the Linux distribution to install on each instance. + + The distributions listed here are official OCI platform images + provided by Oracle. These images are well-tested, actively + maintained, and available across all subscribed regions. + + For marketplace or custom images, select "Custom image OCID" + below and enter the image OCID directly. + +{% for publisher_key in publishers %} +{% if publisher_key == 'oracle' %} +config TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX + bool "Oracle Linux" + help + Select this if you want to use a release of Oracle Linux + as the operating system in your instances. + +{% elif publisher_key == 'ubuntu' %} +config TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU + bool "Ubuntu" + help + Select this if you want to use a release of Ubuntu Linux + as the operating system in your instances. + +{% else %} +config TERRAFORM_OCI_OPERATING_SYSTEM_{{ publisher_key | upper }} + bool "{{ publisher_key | title }}" + help + Select this if you want to use a release of {{ publisher_key | title }} + as the operating system in your instances. + +{% endif %} +{% endfor %} + +config TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM + bool "Custom image OCID" + help + Select this if you want to enter a specific OCID for + an OS image. Use this option for: + + - Marketplace images (not included in automated menu) + - Community images + - Custom-built images + - Older platform image releases + + Note: The automated distribution menu above only includes + official OCI platform images. Marketplace images must be + specified manually using this custom OCID option. + + The image you specify must reside in the same region as + your instances. + + More image choices are available: + + https://docs.oracle.com/en-us/iaas/images/ + +endchoice + +if TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM + +config TERRAFORM_OCI_OS_IMAGE_OCID + string "OS image OCID" + output yaml + help + An image is a template of a virtual hard drive. It + contains the operating system and other software for each + instance. Select an image by specifying the OCID of the + image to use. You can select: + + - An older release than the latest image release + - An older operating system release + - A custom-made image + + More detail is available: + + https://docs.oracle.com/en-us/iaas/Content/Compute/References/bringyourownimage.htm + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_CUSTOM diff --git a/terraform/oci/scripts/image_publisher.j2 b/terraform/oci/scripts/image_publisher.j2 new file mode 100644 index 000000000..8772f7a5d --- /dev/null +++ b/terraform/oci/scripts/image_publisher.j2 @@ -0,0 +1,79 @@ +{# + This template is rendered by gen_kconfig_image script. + + Template variables: + - publisher_key: str (e.g., 'oracle', 'ubuntu') + - publisher_name: str (e.g., 'Oracle Linux') + - publisher_description: str (full description) + - versions: list of (version_key, version_info) tuples (pre-sorted) + - get_release_notes_url: function to generate doc URLs + - get_region_kconfig_name: function to convert region names +#} +{% if publisher_key == 'oracle' %} +if TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX +{% elif publisher_key == 'ubuntu' %} +if TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU +{% else %} +if TERRAFORM_OCI_OPERATING_SYSTEM_{{ publisher_key | upper }} +{% endif %} + +choice + prompt "OS release" +{# versions is a list of (version_key, version_info) tuples from sorted_versions in gen_kconfig_image #} +{% for version_key, version_info in versions | reverse %} +{% if "ARM64" in version_key %} + default TERRAFORM_OCI_OPERATING_SYSTEM_{{ version_key }} if TARGET_ARCH_ARM64 +{% elif "X86" in version_key %} + default TERRAFORM_OCI_OPERATING_SYSTEM_{{ version_key }} if TARGET_ARCH_X86_64 +{% endif %} +{% endfor %} + help + Select the release of {{ publisher_description }} to install on each + instance. + +{% for version_key, version_info in versions %} +config TERRAFORM_OCI_OPERATING_SYSTEM_{{ version_key }} + bool "{{ version_info['friendly_name'] }}" +{% if "ARM64" in version_key %} + depends on TARGET_ARCH_ARM64 +{% elif "GPU" in version_key %} + depends on TARGET_ARCH_X86_64 +{% elif "X86" in version_key %} + depends on TARGET_ARCH_X86_64 +{% endif %} + help + {{ version_info['display_name'] }} + + Image type: {{ version_info.get('image_type', 'Unknown') }} + + Available in regions: {% for region in version_info['region_ocids'].keys() | sort %}{{ region }}{% if not loop.last %}, {% endif %}{% endfor %} + +{% if get_release_notes_url(version_info['display_name']) %} + Image release notes: + {{ get_release_notes_url(version_info['display_name']) }} +{% endif %} + +{% endfor %} +endchoice + +{% for version_key, version_info in versions %} +if TERRAFORM_OCI_OPERATING_SYSTEM_{{ version_key }} + +config TERRAFORM_OCI_OS_IMAGE_OCID + string + output yaml +{# version_info['region_ocids'] is a dict, so .items() is required here #} +{% for region, ocid in version_info['region_ocids'].items() %} + default "{{ ocid }}" if TERRAFORM_OCI_REGION_{{ get_region_kconfig_name(region) }} +{% endfor %} + +endif # TERRAFORM_OCI_OPERATING_SYSTEM_{{ version_key }} + +{% endfor %} +{% if publisher_key == 'oracle' %} +endif # TERRAFORM_OCI_OPERATING_SYSTEM_ORACLE_LINUX +{% elif publisher_key == 'ubuntu' %} +endif # TERRAFORM_OCI_OPERATING_SYSTEM_UBUNTU +{% else %} +endif # TERRAFORM_OCI_OPERATING_SYSTEM_{{ publisher_key | upper }} +{% endif %} diff --git a/terraform/oci/scripts/oci_common.py b/terraform/oci/scripts/oci_common.py new file mode 100644 index 000000000..1485b5275 --- /dev/null +++ b/terraform/oci/scripts/oci_common.py @@ -0,0 +1,285 @@ +#!/usr/bin/env python3 +# ex: set filetype=python: + +""" +Common utilities for OCI Kconfig generation scripts. + +This module provides shared functionality used by gen_kconfig_location, +gen_kconfig_shape, and gen_kconfig_image scripts to avoid code duplication. +""" + +from __future__ import annotations + +import os +import sys +from configparser import ConfigParser +from pathlib import Path +from typing import Any, Optional + +import yaml +from jinja2 import Environment, FileSystemLoader + + +def get_default_region() -> str: + """ + Get the default OCI region from the ~/.oci/config file. + + Returns: + str: Default region, or 'us-ashburn-1' if no default is found. + """ + config_path = os.path.expanduser("~/.oci/config") + if os.path.exists(config_path): + try: + config = ConfigParser() + config.read(config_path) + if "DEFAULT" in config: + return config["DEFAULT"].get("region", "us-ashburn-1") + except Exception as e: + print(f"Warning: Error reading OCI config file: {e}", file=sys.stderr) + return "us-ashburn-1" + + +def get_default_compartment() -> Optional[str]: + """ + Get the default compartment OCID from OCI config. + + Returns: + str: Tenancy OCID (root compartment), or None on error + """ + try: + config = get_oci_config() + return config["tenancy"] + except Exception as e: + print(f"Error getting compartment: {e}", file=sys.stderr) + return None + + +def get_subscribed_regions(quiet: bool = False) -> list[str]: + """ + Get all subscribed regions for the tenancy. + + Args: + quiet (bool): Suppress debug messages + + Returns: + list: List of subscribed region names + """ + try: + config = get_oci_config() + identity = create_identity_client() + + region_subs = identity.list_region_subscriptions(config["tenancy"]).data + subscribed = [r.region_name for r in region_subs if r.status == "READY"] + + if not quiet: + print( + f"Found {len(subscribed)} subscribed regions: {', '.join(subscribed)}", + file=sys.stderr, + ) + + return subscribed + + except Exception as e: + print(f"Error getting subscribed regions: {e}", file=sys.stderr) + # Fallback to default region + return [get_default_region()] + + +def get_jinja2_environment(template_path: Optional[str] = None) -> Environment: + """ + Create a standardized Jinja2 environment for template rendering. + + Args: + template_path (str): Path to template directory. If None, uses caller's directory. + + Returns: + Environment: Configured Jinja2 Environment object + """ + if template_path is None: + template_path = Path(__file__).parent + + return Environment( + loader=FileSystemLoader(template_path), + trim_blocks=True, + lstrip_blocks=True, + ) + + +def load_yaml_config( + filename: str, quiet: bool = False, default: Optional[Any] = None +) -> Any: + """ + Load a YAML configuration file with consistent error handling. + + This function provides standardized YAML loading used across all + gen_kconfig_* scripts for loading configuration files like + region_friendly_names.yml, catalog_shapes.yml, and + publisher_definitions.yml. + + Args: + filename (str): Name of YAML file (not full path - will be looked up + in script directory) + quiet (bool): Suppress warning messages to stderr + default: Default value to return on error (default: empty dict) + + Returns: + Data loaded from YAML file, or default value on error + """ + if default is None: + default = {} + + yaml_path = Path(__file__).parent / filename + + try: + with open(yaml_path, "r") as f: + data = yaml.safe_load(f) + return data if data else default + except FileNotFoundError: + if not quiet: + print(f"Warning: {yaml_path} not found. Using defaults.", file=sys.stderr) + return default + except yaml.YAMLError as e: + if not quiet: + print( + f"Warning: Error parsing {yaml_path}: {e}. Using defaults.", + file=sys.stderr, + ) + return default + + +def get_oci_config(region: Optional[str] = None) -> dict[str, Any]: + """ + Get OCI configuration with optional region override. + + This provides a centralized way to load OCI config and optionally + override the region, with consistent error handling. + + Args: + region (str): Optional region to override config default + + Returns: + dict: OCI configuration dictionary + + Raises: + ConfigFileNotFound: If OCI config file doesn't exist + Exception: For other configuration errors + """ + # Lazy import - only load OCI SDK when actually needed + import oci + + config = oci.config.from_file() + if region: + config["region"] = region + return config + + +def create_identity_client(region: Optional[str] = None) -> oci.identity.IdentityClient: + """ + Create an OCI Identity client with optional region override. + + Args: + region (str): Optional region to use instead of config default + + Returns: + oci.identity.IdentityClient: Configured identity client + + Raises: + ConfigFileNotFound: If OCI config file doesn't exist + Exception: For other initialization errors + """ + # Lazy import - only load OCI SDK when actually needed + import oci + + config = get_oci_config(region) + return oci.identity.IdentityClient(config) + + +def create_compute_client(region: Optional[str] = None) -> oci.core.ComputeClient: + """ + Create an OCI Compute client with optional region override. + + Args: + region (str): Optional region to use instead of config default + + Returns: + oci.core.ComputeClient: Configured compute client + + Raises: + ConfigFileNotFound: If OCI config file doesn't exist + Exception: For other initialization errors + """ + # Lazy import - only load OCI SDK when actually needed + import oci + + config = get_oci_config(region) + return oci.core.ComputeClient(config) + + +def get_all_region_keys(quiet: bool = False) -> dict[str, str]: + """ + Get all OCI regions with their official region keys from the OCI API. + + The region key is the 3-letter code (e.g., 'ORD' for us-chicago-1) + that OCI uses in its API responses. This is the authoritative source + for region codes rather than hardcoding a mapping. + + Args: + quiet (bool): Suppress debug messages + + Returns: + dict: Dictionary mapping region_name -> region_key (e.g., 'us-chicago-1' -> 'ORD') + """ + try: + identity = create_identity_client() + + # Get all regions - this includes their official region keys + all_regions = identity.list_regions().data + + region_key_map = {} + for region in all_regions: + region_key_map[region.name] = region.key + + if not quiet: + print( + f"Loaded {len(region_key_map)} region key mappings from OCI API", + file=sys.stderr, + ) + + return region_key_map + + except Exception as e: + if not quiet: + print( + f"Warning: Could not load region keys from OCI API: {e}", + file=sys.stderr, + ) + print("Using fallback region key generation", file=sys.stderr) + return {} + + +def get_region_kconfig_name( + region_name: str, region_key_map: Optional[dict[str, str]] = None +) -> str: + """ + Convert OCI region name to Kconfig region constant name. + + Uses the official region key from the OCI API when available, + falling back to a generated name if the API is not accessible. + + Args: + region_name (str): OCI region name (e.g., 'us-chicago-1') + region_key_map (dict): Optional mapping from region_name to region_key. + If None, generates from region name. + + Returns: + str: Kconfig constant name (e.g., 'ORD' for us-chicago-1) + """ + if region_key_map and region_name in region_key_map: + return region_key_map[region_name] + + # Fallback: generate from region name + # Take first 3 letters of the location part + parts = region_name.split("-") + if len(parts) >= 2: + return parts[1][:3].upper() + return region_name[:3].upper() diff --git a/terraform/oci/scripts/publisher_definitions.yml b/terraform/oci/scripts/publisher_definitions.yml new file mode 100644 index 000000000..5d382163c --- /dev/null +++ b/terraform/oci/scripts/publisher_definitions.yml @@ -0,0 +1,148 @@ +# OCI Image Publisher Definitions +# +# This file defines known OS image publishers in Oracle Cloud Infrastructure +# and their image naming patterns for automatic image discovery. +# +# Purpose: +# When generating Kconfig.images, the gen_kconfig_image script uses these +# publisher definitions to: +# - Recognize and categorize OS images by their display names +# - Generate organized Kconfig menus grouped by Linux distribution +# - Provide friendly names and descriptions for each distribution +# +# Dynamic Discovery: +# In addition to these known publishers, the gen_kconfig_image script can +# dynamically discover new Linux distributions by analyzing image naming +# patterns. Discovered publishers are marked with [NEW] in the generated +# Kconfig output. +# +# Last Verified: 2025-10-21 +# Total Publishers: 10 +# +# Format: +# ------- +# publisher_key: +# publisher_name: "Display Name" +# description: "Full Description" +# display_name_patterns: +# - "regex-pattern-1" +# - "regex-pattern-2" +# priority: N +# +# Fields: +# publisher_key: Short identifier (lowercase, used in Kconfig symbols) +# publisher_name: Human-friendly publisher/company name +# description: Full description shown in Kconfig help text +# display_name_patterns: List of regex patterns to match image display names +# priority: Display order (lower numbers appear first) +# +# How to update this file: +# ------------------------ +# When Oracle adds new Linux distributions or you want to customize the list: +# +# 1. Find available images in your OCI tenancy: +# $ oci compute image list --compartment-id \ +# --sort-by DISPLAYNAME --all +# +# 2. Identify the image naming pattern from the display_name field. +# Examples: +# - "Oracle-Linux-9.6-2025.06.17-0" -> Pattern: "Oracle-Linux-.*" +# - "Canonical-Ubuntu-22.04-2024.10.14-0" -> Pattern: "Canonical-Ubuntu-.*" +# - "AlmaLinux-8-2024.10.11-0" -> Pattern: "AlmaLinux-.*" +# +# 3. Add a new publisher entry following the format above. Choose: +# - A unique publisher_key (lowercase, no spaces) +# - A descriptive publisher_name and description +# - Regex patterns that match all variants of that distribution +# - A priority number (higher numbers appear later in menus) +# +# 4. Update the "Last Verified" date and "Total Publishers" count above. +# +# 5. After updating this file, regenerate the Kconfig.images file: +# $ cd terraform/oci/scripts +# $ ./gen_kconfig_image > ../kconfigs/Kconfig.images +# +# 6. You can verify your patterns match correctly by running: +# $ ./gen_kconfig_image --publishers +# +# Notes: +# ------ +# - Patterns are evaluated as Python regex with re.IGNORECASE flag +# - The script processes images in priority order (lower priority first) +# - Only Linux distributions are included (no Windows, BSD, etc.) +# - Dynamic discovery can find new distributions not listed here +# +# Publisher Definitions: +# ---------------------- + +oracle: + publisher_name: "Oracle" + description: "Oracle Linux" + display_name_patterns: + - "Oracle-Linux-.*" + - "Oracle Linux .*" + - "Oracle-Autonomous-Linux-.*" + priority: 1 + +ubuntu: + publisher_name: "Canonical" + description: "Ubuntu" + display_name_patterns: + - "Canonical-Ubuntu-.*" + priority: 2 + +centos: + publisher_name: "CentOS" + description: "CentOS Linux" + display_name_patterns: + - "CentOS-\\d+-.*" + priority: 3 + +almalinux: + publisher_name: "AlmaLinux" + description: "AlmaLinux OS" + display_name_patterns: + - "AlmaLinux-.*" + priority: 4 + +rocky: + publisher_name: "Rocky Enterprise" + description: "Rocky Linux" + display_name_patterns: + - "Rocky-Linux-.*" + priority: 5 + +suse: + publisher_name: "SUSE" + description: "SUSE Linux Enterprise" + display_name_patterns: + - "SUSE-.*" + priority: 6 + +opensuse: + publisher_name: "openSUSE" + description: "openSUSE Linux" + display_name_patterns: + - "openSUSE-.*" + priority: 7 + +redhat: + publisher_name: "Red Hat" + description: "Red Hat Enterprise Linux" + display_name_patterns: + - "Red-Hat-.*" + priority: 8 + +debian: + publisher_name: "Debian" + description: "Debian Linux" + display_name_patterns: + - "Debian-.*" + priority: 9 + +fedora: + publisher_name: "Fedora" + description: "Fedora Linux" + display_name_patterns: + - "Fedora-.*" + priority: 10 diff --git a/terraform/oci/scripts/region_friendly_names.yml b/terraform/oci/scripts/region_friendly_names.yml new file mode 100644 index 000000000..1e61f3bff --- /dev/null +++ b/terraform/oci/scripts/region_friendly_names.yml @@ -0,0 +1,94 @@ +# OCI Region Friendly Names +# +# This file maps OCI region identifiers to human-friendly display names +# used in the kdevops Kconfig menus. +# +# Canonical Source: +# https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm +# (Official Oracle Cloud Infrastructure Regions and Availability Domains page) +# +# IMPORTANT: This URL points to HTML documentation, not an API. The +# documentation format and content can change at any time. Use the OCI +# CLI for programmatic access: oci iam region list +# +# Last Verified: 2025-10-19 +# Total Regions: 41 +# +# Format: +# region-identifier: "Friendly Display Name" +# +# Ordering Requirement: +# The regions below are maintained in the same order as they appear in +# Oracle's official documentation table. This makes verification easier +# and provides a consistent ordering for the generated Kconfig. +# +# How to update this file: +# ----------------------- +# When Oracle adds new regions or you want to customize the display names: +# +# 1. Find the official region identifier from OCI: +# $ oci iam region-subscription list +# +# 2. Look up the region's friendly name from Oracle's documentation: +# https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm +# +# 3. Add a new entry following the format above. Use the pattern: +# " ()" +# +# Examples: +# - "US West (Phoenix)" +# - "Europe (Frankfurt)" +# - "Asia Pacific (Tokyo)" +# +# 4. Maintain the same order as shown in Oracle's documentation table. +# +# 5. Update the "Last Verified" date and "Total Regions" count above. +# +# 6. After updating this file, regenerate the Kconfig.location file: +# $ cd terraform/oci/scripts +# $ ./gen_kconfig_location > ../kconfigs/Kconfig.location +# +# Region Mappings: +# ---------------- + +ap-sydney-1: "Australia East (Sydney)" +ap-melbourne-1: "Australia Southeast (Melbourne)" +sa-saopaulo-1: "Brazil East (Sao Paulo)" +sa-vinhedo-1: "Brazil Southeast (Vinhedo)" +ca-montreal-1: "Canada Southeast (Montreal)" +ca-toronto-1: "Canada Southeast (Toronto)" +sa-santiago-1: "Chile Central (Santiago)" +sa-valparaiso-1: "Chile West (Valparaiso)" +sa-bogota-1: "Colombia Central (Bogota)" +eu-paris-1: "France Central (Paris)" +eu-marseille-1: "France South (Marseille)" +eu-frankfurt-1: "Germany Central (Frankfurt)" +ap-hyderabad-1: "India South (Hyderabad)" +ap-mumbai-1: "India West (Mumbai)" +ap-batam-1: "Indonesia North (Batam)" +il-jerusalem-1: "Israel Central (Jerusalem)" +eu-milan-1: "Italy Northwest (Milan)" +ap-osaka-1: "Japan Central (Osaka)" +ap-tokyo-1: "Japan East (Tokyo)" +mx-queretaro-1: "Mexico Central (Queretaro)" +mx-monterrey-1: "Mexico Northeast (Monterrey)" +eu-amsterdam-1: "Netherlands Northwest (Amsterdam)" +me-riyadh-1: "Saudi Arabia Central (Riyadh)" +me-jeddah-1: "Saudi Arabia West (Jeddah)" +eu-jovanovac-1: "Serbia Central (Jovanovac)" +ap-singapore-1: "Singapore (Singapore)" +ap-singapore-2: "Singapore West (Singapore)" +af-johannesburg-1: "South Africa Central (Johannesburg)" +ap-seoul-1: "South Korea Central (Seoul)" +ap-chuncheon-1: "South Korea North (Chuncheon)" +eu-madrid-1: "Spain Central (Madrid)" +eu-stockholm-1: "Sweden Central (Stockholm)" +eu-zurich-1: "Switzerland North (Zurich)" +me-abudhabi-1: "UAE Central (Abu Dhabi)" +me-dubai-1: "UAE East (Dubai)" +uk-london-1: "UK South (London)" +uk-cardiff-1: "UK West (Newport)" +us-ashburn-1: "US East (Ashburn)" +us-chicago-1: "US Midwest (Chicago)" +us-phoenix-1: "US West (Phoenix)" +us-sanjose-1: "US West (San Jose)" diff --git a/terraform/oci/scripts/regions.j2 b/terraform/oci/scripts/regions.j2 new file mode 100644 index 000000000..cc1198853 --- /dev/null +++ b/terraform/oci/scripts/regions.j2 @@ -0,0 +1,24 @@ +choice + prompt "OCI Region" + default TERRAFORM_OCI_REGION_{{ default_region }} + help + A region is a collection of geographically co-located data + centers that share data and hardware resources. For more + information: + + https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm + + Using this menu, select the region in which you wish to + deploy your kdevops resources. Your tenancy must be + subscribed to the region you select here. Use: + + $ oci iam region-subscription list + + for a list of regions to which your tenancy subscribes. + +{% for region in regions %} +config TERRAFORM_OCI_REGION_{{ region['region_code'] }} + bool "{{ region['friendly_name'] }}" + +{% endfor %} +endchoice diff --git a/terraform/oci/scripts/shape_families.j2 b/terraform/oci/scripts/shape_families.j2 new file mode 100644 index 000000000..fffa4c1dd --- /dev/null +++ b/terraform/oci/scripts/shape_families.j2 @@ -0,0 +1,44 @@ +choice + prompt "OCI shape family" + default TERRAFORM_OCI_SHAPE_FAMILY_FLEX + help + This option selects the class of virtual hardware (CPUs and + memory) to provision for each target node. Most CPU + architectures, including x86, run two threads per physical + core, so one OCPU is the equal of two vCPUs for x86-based + compute. + + Which shapes are available is limited by your subscription + and what hardware has been deployed in your selected region. + +config TERRAFORM_OCI_SHAPE_FAMILY_GENERIC + bool "Generic shapes" + help + These shapes are recommended for developers who do not + require a specific model of CPU for their workflows. + +config TERRAFORM_OCI_SHAPE_FAMILY_FLEX + bool "Flex shapes" + help + A flexible shape is a virtual machine that lets you + customize the number of OCPUs and the amount of memory + per instance. The network bandwidth and number of VNICs + scale proportionately with the number of OCPUs. + +config TERRAFORM_OCI_SHAPE_FAMILY_FIXED + bool "Fixed shapes" + help + A fixed shape is a virtual machine with a predetermined + number of OCPUs and amount of memory. These shapes offer + consistent performance characteristics with configurations + optimized for common workload patterns. + +config TERRAFORM_OCI_SHAPE_FAMILY_BARE_METAL + bool "Bare metal" + help + A bare metal shape is a whole physical machine without + virtualization. This gives deterministic performance + characteristics but is less configurable than a flex + shape. + +endchoice diff --git a/terraform/oci/scripts/shape_family.j2 b/terraform/oci/scripts/shape_family.j2 new file mode 100644 index 000000000..ec0c762ca --- /dev/null +++ b/terraform/oci/scripts/shape_family.j2 @@ -0,0 +1,57 @@ +if TERRAFORM_OCI_SHAPE_FAMILY_{{ family_name }} + +choice + prompt "Shape type" + default TERRAFORM_OCI_SHAPE_{{ shapes[0]['shape_name'].upper().replace('.', '_').replace('-', '_') }} + help + Select the specific shape configuration within this family. + Each shape provides different combinations of OCPUs, memory, + storage, and networking capacity. + +{% for shape in shapes %} +config TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} + bool "{{ shape['shape_name'] }}" +{% if 'x86_64' in shape['cpu_isa'] %} + depends on TARGET_ARCH_X86_64 +{% elif 'arm64' in shape['cpu_isa'] %} + depends on TARGET_ARCH_ARM64 +{% endif %} + help +{% if shape['is_flex'] %} + Flexible shape: OCPU and memory can be customized. +{% else %} + OCPU count: {{ shape['ocpus'] }} + Memory: {{ shape['memory_gb'] }} GB +{% endif %} + Architecture: {{ shape['cpu_isa'] }} + Network: {{ shape['network_performance'] }} +{% if shape['storage'] != 'Block storage only' %} + Local storage: {{ shape['storage'] }} +{% endif %} +{% if shape['gpu'] != 'None' %} + GPU: {{ shape['gpu'] }} +{% endif %} +{% if shape['is_bare_metal'] %} + Bare metal instance. +{% endif %} +{% if 'processor' in shape %} + Processor: {{ shape['processor'] }} +{% endif %} +{% if shape['is_catalog_shape'] %} + + NOTE: This shape may require service limit increases and may not + be available in all regions. Contact Oracle support to request + access if needed. +{% endif %} + +{% endfor %} +endchoice + +config TERRAFORM_OCI_SHAPE + string + output yaml +{% for shape in shapes %} + default "{{ shape['shape_name'] }}" if TERRAFORM_OCI_SHAPE_{{ shape['shape_name'].upper().replace('.', '_').replace('-', '_') }} +{% endfor %} + +endif # TERRAFORM_OCI_SHAPE_FAMILY_{{ family_name }}