
Oci
- 14 installs
- 22 repo stars
- Updated May 28, 2026
- acedergren/agentic-tools
oci is a Claude Code router skill that triages broad OCI architecture reviews and migrations and routes each domain to its specialist OCI skill.
About
oci (best-practices router) is a Claude Code skill used as the entry point for broad OCI architecture reviews, migration triage, and deciding which OCI skill applies. A developer uses it when a request spans more than one OCI domain or the correct specialist skill is unclear. It routes networking, IAM, landing-zone, Terraform, compute, database, and security questions to owner skills and checks cross-cutting risks.
- Entry-point router for broad OCI architecture reviews
- Routes each domain to the owner OCI skill
- Well-Architected and CIS-style cross-domain risk checks
Oci by the numbers
- 14 all-time installs (skills.sh)
- Ranked #829 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
oci capabilities & compatibility
Free; routing guidance with no external service.
- Capabilities
- architecture review · skill routing
- Works with
- oracle
- Use cases
- devops · security audit
- Pricing
- Free
What oci says it does
Use it first when the request spans more than one OCI domain or the correct specialist skill is unclear.
NEVER treat this router as the source of truth for pricing, model catalogs, quotas, or service limits.
npx skills add https://github.com/acedergren/agentic-tools --skill ociAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14 |
|---|---|
| repo stars | ★ 22 |
| Last updated | May 28, 2026 |
| Repository | acedergren/agentic-tools ↗ |
What it does
Route broad OCI architecture reviews and migration triage to the correct specialist OCI skill.
Who is it for?
Cross-domain OCI architecture reviews and migration triage where the specialist skill is unclear.
Skip if: A narrow already-identified service task, or requests only asking to find or install skills.
When should I use this skill?
Use when reviewing OCI architecture, avoiding OCI anti-patterns, planning an Oracle Cloud migration, or choosing which OCI skill applies.
By the numbers
- 12-row routing table to specialist OCI skills
- 8-entry hot-word routing table
Files
OCI Architecture Review Router
Use this skill as the entry point for broad OCI architecture reviews, migration triage, and "which OCI skill applies?" decisions. Keep service-specific facts in the narrower skills so high-drift guidance has one owner.
When to Use
Load this skill for: the user asks to "review OCI architecture", "avoid OCI anti-patterns", "plan an Oracle Cloud migration", "evaluate OCI Well-Architected risks", or "choose which OCI skill applies".
Use it first when the request spans more than one OCI domain or the correct specialist skill is unclear.
Do NOT load this skill when
Do not load this skill for a narrow, already-identified service task:
| User intent | Load instead |
|---|---|
| VCN, subnet, peering, DRG, VPN, FastConnect | oci/networking-management |
| IAM policy, identity domain, dynamic group, 403/404 auth | oci/iam-identity-management |
| Landing zone, compartments, Security Zones, Cloud Guard recipes | oci/landing-zones |
| Terraform, Resource Manager, state, imports, drift | oci/infrastructure-as-code |
| Compute shapes, capacity, boot volumes, instance principals | oci/compute-management |
| Autonomous AI Database / ADB operations, SQLcl, wallet, ECPU tuning | oci/oracle-dba |
| Billing, egress, budgets, Resource Scheduler savings | oci/finops-cost-optimization |
| Vault secrets, KMS, rotation, secret replication | oci/secrets-management |
| OCI Generative AI, model choice, RAG, rate limits | oci/genai-services |
| Events rules, CloudEvents, Functions, Streaming, Notifications | oci/oci-events |
| ZPR, Bastion, Cloud Guard vs Security Zones, security-control routing | oci/oci-security-control-plane |
When the request is only asking to find or install skills, use find-skills instead.
Architecture Review Flow
1. Identify the workload boundary: tenancy, compartments, regions, network topology, identity model, data stores, and automation surface. 2. Route each domain to the owner skill above before giving service-specific guidance. 3. Check cross-cutting risks: region/realm support, IAM blast radius, network overlap, private connectivity, data residency, logging/monitoring, cost controls, backup/DR, and supportability. 4. Verify drift-prone facts against current Oracle docs before quoting limits, prices, model catalogs, or service availability.
NEVER Do This
- NEVER treat this router as the source of truth for pricing, model catalogs, quotas, or service limits. Route to the owner skill and verify current Oracle docs.
- NEVER repeat detailed service guidance here when a narrower skill owns it.
- NEVER state that VCN CIDRs are simply immutable. Oracle supports adding and modifying VCN CIDR ranges with restrictions; the architecture risk is poor upfront address planning and overlap.
- NEVER enable Cloud Guard or Security Zone responders in production before testing the exact recipe and automation impact in a lower environment.
- NEVER hardcode tenancy-specific availability-domain names; query them from OCI APIs or Terraform data sources.
Hot Word Routing
| Hot words | Route |
|---|---|
OCI VCN, DRG, FastConnect, Service Gateway, NSG | oci/networking-management |
identity domain, IDCS, dynamic group, policy, 403 | oci/iam-identity-management |
ADB, Autonomous AI Database, wallet, SQLcl, ECPU | oci/oracle-dba |
Vault, KMS, secret rotation, BASE64, replication | oci/secrets-management |
OCI GenAI, Command A, Llama, Gemini, gpt-oss, RAG | oci/genai-services |
Events, CloudEvents, Functions, Streaming, Notifications | oci/oci-events |
Terraform, Resource Manager, state, import, drift | oci/infrastructure-as-code |
ZPR, Zero Trust Packet Routing, Bastion, Managed SSH, security control | oci/oci-security-control-plane |
Reference Files
Load `references/oci-well-architected-checklist.md` only when the user asks for a formal OCI architecture review checklist, CIS-style review, or cross-domain risk assessment. Do not load it for narrow service questions.
Arguments
$ARGUMENTS: Optional architecture scope, workload name, target environment, migration source, or review objective. When empty, infer the narrowest safe review scope from the conversation and route to specialist skills before making service-specific claims.
OCI Well-Architected Framework Checklist
Five Pillars Overview
Pillar 1: Security and Compliance
| Focus Area | Best Practice | CLI Verification |
|---|---|---|
| User Authentication | Enable MFA for all IAM users | oci iam user list --query "data[?\"is-mfa-activated\"==\false\]" |
| Authorization | Use least privilege policies | Review policies for all-resources or any-user |
| Data Encryption | Enable encryption at rest | oci vault secret list --compartment-id <id> |
| Network Security | Use NSGs over Security Lists | oci network nsg list --compartment-id <id> |
| Audit Logging | Enable audit logs for all compartments | oci audit event list --compartment-id <id> |
Pillar 2: Reliability and Resilience
| Focus Area | Best Practice | CLI Verification |
|---|---|---|
| High Availability | Deploy across multiple ADs | Check instance distribution |
| Backup Strategy | Configure automatic backups | oci bv backup list --compartment-id <id> |
| Disaster Recovery | Set up cross-region replication | oci os replication-policy list |
| Load Balancing | Use regional load balancers | oci lb load-balancer list --compartment-id <id> |
Pillar 3: Performance and Cost Optimization
| Focus Area | Best Practice | CLI Verification |
|---|---|---|
| Right-Sizing | Match instance shapes to workload | Review CPU/Memory utilization metrics |
| Reserved Capacity | Use committed pricing for predictable workloads | oci limits value list |
| Storage Tiers | Use appropriate storage classes | Check for overprovisioned volumes |
| Networking | Use Service Gateway for OCI services | oci network service-gateway list |
Pillar 4: Operational Efficiency
| Focus Area | Best Practice | CLI Verification |
|---|---|---|
| Infrastructure as Code | Use Terraform for all resources | Check for Resource Manager stacks |
| Monitoring | Set up alarms for critical metrics | oci monitoring alarm list --compartment-id <id> |
| Automation | Use OCI Events for automation | oci events rule list --compartment-id <id> |
| Tagging | Implement mandatory tagging | oci iam tag-namespace list --compartment-id <id> |
Pillar 5: Distributed Cloud
| Focus Area | Best Practice | CLI Verification |
|---|---|---|
| Multi-Region | Deploy critical workloads in multiple regions | Review region distribution |
| Hybrid Cloud | Use FastConnect for on-premises connectivity | oci network fast-connect-provider-service list |
| Edge | Use Content Delivery for global distribution | Check CDN configurations |
CIS OCI Foundations Benchmark Controls
Identity and Access Management
# 1.1 Ensure MFA is enabled for all users
oci iam user list --all --query "data[?\"is-mfa-activated\"==\`false\`].{Name:name,OCID:id}"
# 1.2 Ensure API keys rotate every 90 days
oci iam user api-key list --user-id <user-ocid> --query "data[?\"time-created\" < '\`date -v-90d +%Y-%m-%dT%H:%M:%S\`']"
# 1.3 Ensure no policies use "any-user"
oci iam policy list --compartment-id <tenancy-ocid> --all --query "data[?contains(statements[],'any-user')]"Networking
# 2.1 Ensure no security lists allow 0.0.0.0/0 ingress
oci network security-list list --compartment-id <id> --all --query "data[].{Name:\"display-name\",Rules:\"ingress-security-rules\"[?source=='0.0.0.0/0']}"
# 2.2 Ensure VCN Flow Logs are enabled
oci network flow-log list --compartment-id <id>
# 2.3 Ensure Service Gateway is used for OCI services
oci network service-gateway list --compartment-id <id>Logging and Monitoring
# 3.1 Ensure Audit Log retention is at least 365 days
# Audit logs are retained for 365 days by default and cannot be changed
# 3.2 Ensure Cloud Guard is enabled
oci cloud-guard target list --compartment-id <tenancy-ocid>
# 3.3 Ensure VCN Flow Logs are enabled for all subnets
oci network subnet list --compartment-id <id> --query "data[?!\"vcn-id\"]"Storage
# 4.1 Ensure Object Storage buckets are not public
oci os bucket list --compartment-id <id> --query "data[?\"public-access-type\"!='NoPublicAccess']"
# 4.2 Ensure boot volumes are encrypted with Customer-Managed Keys
oci bv boot-volume list --compartment-id <id> --query "data[?!\"kms-key-id\"]"
# 4.3 Ensure block volumes are encrypted with Customer-Managed Keys
oci bv volume list --compartment-id <id> --query "data[?!\"kms-key-id\"]"Quick Compliance Check Script
#!/bin/bash
# OCI Quick Compliance Check
COMPARTMENT_ID="$1"
echo "=== Security Checks ==="
echo "Public buckets:"
oci os bucket list --compartment-id $COMPARTMENT_ID --query "data[?\"public-access-type\"!='NoPublicAccess'].name" --output table
echo "Security lists with 0.0.0.0/0:"
oci network security-list list --compartment-id $COMPARTMENT_ID --all --query "data[].{Name:\"display-name\"}" --output table
echo "=== Reliability Checks ==="
echo "Instances without backups:"
# Compare instance list with backup list
echo "=== Cost Checks ==="
echo "Stopped instances (still incurring boot volume cost):"
oci compute instance list --compartment-id $COMPARTMENT_ID --lifecycle-state STOPPED --query "data[].{Name:\"display-name\",Shape:shape}" --output tableRemediation Priority Matrix
| Finding | Impact | Effort | Priority |
|---|---|---|---|
| Public S3 bucket | Critical | Low | P0 - Fix immediately |
| No MFA enabled | High | Low | P1 - Fix within 24h |
| Open 22/3389 to 0.0.0.0/0 | High | Low | P1 - Fix within 24h |
| No encryption at rest | High | Medium | P2 - Fix within 1 week |
| No backups configured | Medium | Low | P2 - Fix within 1 week |
| Missing tags | Low | Low | P3 - Fix within 1 month |
| Over-provisioned instances | Low | Medium | P3 - Fix within 1 month |
OCI Compute Reference
Use this as a source map for compute shape, instance, and capacity work.
Official Oracle Sources
- Compute overview: https://docs.oracle.com/en-us/iaas/Content/Compute/Concepts/computeoverview.htm
- Compute shapes: https://docs.oracle.com/en-us/iaas/Content/Compute/References/computeshapes.htm
- Launching an instance: https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/launchinginstance.htm
- Instance principals: https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm
- Resource Scheduler: https://docs.oracle.com/en-us/iaas/Content/resource-scheduler/tasks/getting-started_resource_scheduler.htm
Load Guidance
Open the shape reference and price list before quoting shape availability, memory ratios, GPU shape names, or prices.
OCI Database Cloud Service CLI Reference
Database System Operations
List Database Systems
# List all DB systems in compartment
oci db system list --compartment-id <compartment-ocid>
# List with filters
oci db system list --compartment-id <compartment-ocid> \
--lifecycle-state AVAILABLE \
--display-name "prod-*"Create Database System
# Create VM DB System
oci db system launch \
--compartment-id <compartment-ocid> \
--availability-domain <ad-name> \
--subnet-id <subnet-ocid> \
--shape "VM.Standard2.4" \
--cpu-core-count 4 \
--database-edition "ENTERPRISE_EDITION" \
--admin-password "<secure-password>" \
--db-name "MYDB" \
--db-version "19.0.0.0" \
--display-name "prod-db-1" \
--hostname "prod-db-1" \
--initial-data-storage-size-in-gb 256 \
--node-count 1 \
--ssh-authorized-keys-file ~/.ssh/id_rsa.pub
# Create RAC DB System (2 nodes)
oci db system launch \
--compartment-id <compartment-ocid> \
--availability-domain <ad-name> \
--subnet-id <subnet-ocid> \
--shape "VM.Standard2.8" \
--cpu-core-count 8 \
--cluster-name "prodrac" \
--database-edition "ENTERPRISE_EDITION_EXTREME_PERFORMANCE" \
--admin-password "<secure-password>" \
--db-name "RACDB" \
--db-version "19.0.0.0" \
--display-name "prod-rac-cluster" \
--hostname "prod-rac" \
--initial-data-storage-size-in-gb 512 \
--node-count 2 \
--ssh-authorized-keys-file ~/.ssh/id_rsa.pubScale Database System
# Scale CPU (online for Flex shapes)
oci db system update \
--db-system-id <db-system-ocid> \
--cpu-core-count 8
# Scale storage (online)
oci db system update \
--db-system-id <db-system-ocid> \
--data-storage-size-in-gbs 512Database Operations
# List databases in a DB system
oci db database list \
--compartment-id <compartment-ocid> \
--db-system-id <db-system-ocid>
# Create additional database in existing system
oci db database create \
--db-system-id <db-system-ocid> \
--admin-password "<secure-password>" \
--db-name "NEWDB" \
--db-version "19.0.0.0"
# Delete database (CAUTION)
oci db database delete \
--database-id <database-ocid> \
--perform-final-backup trueBackup and Recovery
Manual Backups
# Create manual backup
oci db backup create \
--database-id <database-ocid> \
--display-name "pre-upgrade-backup"
# List backups
oci db backup list \
--compartment-id <compartment-ocid> \
--database-id <database-ocid>
# Restore from backup
oci db database restore \
--database-id <database-ocid> \
--latest true
# Restore to point-in-time
oci db database restore \
--database-id <database-ocid> \
--timestamp "2024-01-15T10:30:00.000Z"Automatic Backup Configuration
# Enable automatic backups
oci db database update \
--database-id <database-ocid> \
--auto-backup-enabled true \
--recovery-window-in-days 30
# Configure backup destination (custom)
oci db database update \
--database-id <database-ocid> \
--auto-backup-enabled true \
--backup-destination '[{"type":"OBJECT_STORE"}]'Data Guard Configuration
Enable Data Guard
# Create standby database
oci db data-guard-association create \
--database-id <primary-database-ocid> \
--creation-type "NewDbSystem" \
--database-admin-password "<password>" \
--protection-mode "MAXIMUM_PERFORMANCE" \
--transport-type "ASYNC" \
--availability-domain <standby-ad> \
--display-name "standby-db-1" \
--hostname "standby-db-1" \
--subnet-id <standby-subnet-ocid>
# List Data Guard associations
oci db data-guard-association list \
--database-id <database-ocid>Switchover and Failover
# Switchover (planned, no data loss)
oci db data-guard-association switchover \
--database-id <primary-database-ocid> \
--data-guard-association-id <association-ocid> \
--database-admin-password "<password>"
# Failover (emergency, potential data loss)
oci db data-guard-association failover \
--database-id <standby-database-ocid> \
--data-guard-association-id <association-ocid> \
--database-admin-password "<password>"
# Reinstate old primary as standby
oci db data-guard-association reinstate \
--database-id <new-standby-database-ocid> \
--data-guard-association-id <association-ocid> \
--database-admin-password "<password>"Patching and Maintenance
View Available Patches
# List available patches
oci db patch list \
--db-system-id <db-system-ocid>
# Get patch details
oci db patch get \
--patch-id <patch-ocid>Apply Patches
# Apply patch to DB system
oci db db-system-patch-history-entry list \
--db-system-id <db-system-ocid>
# Check patch history
oci db patch-history list \
--db-system-id <db-system-ocid>ExaDB-D and ExaDB-C@C Operations
Exadata Infrastructure
# List Exadata infrastructures
oci db exadata-infrastructure list \
--compartment-id <compartment-ocid>
# Get Exadata infrastructure details
oci db exadata-infrastructure get \
--exadata-infrastructure-id <infra-ocid>VM Clusters
# List VM clusters
oci db vm-cluster list \
--compartment-id <compartment-ocid>
# Create VM cluster
oci db vm-cluster create \
--compartment-id <compartment-ocid> \
--exadata-infrastructure-id <infra-ocid> \
--vm-cluster-network-id <network-ocid> \
--cpu-core-count 8 \
--display-name "prod-vmcluster" \
--gi-version "19.0.0.0" \
--ssh-public-keys-file ~/.ssh/id_rsa.pubCommon Troubleshooting
Connection Issues
# Verify DB system is running
oci db system get --db-system-id <ocid> --query "data.\"lifecycle-state\""
# Check listeners
oci db node list --compartment-id <id> --db-system-id <db-system-ocid>
# Verify NSG rules
oci network nsg-security-rule list --nsg-id <nsg-ocid>Performance Diagnostics
# Get DB system metrics
oci monitoring metric-data summarize-metrics-data \
--compartment-id <compartment-ocid> \
--namespace "oci_database" \
--query-text 'CpuUtilization[1m]{resourceId="<db-system-ocid>"}.mean()'Cost Optimization Commands
# Find stopped DB systems (still incurring storage costs)
oci db system list --compartment-id <id> --lifecycle-state STOPPED
# List DB systems by shape for right-sizing analysis
oci db system list --compartment-id <id> --query "data[].{Name:\"display-name\",Shape:shape,CPUs:\"cpu-core-count\"}"
# Check backup storage usage
oci db backup list --compartment-id <id> --query "data[].{DB:\"database-id\",Size:\"database-size-in-gbs\",Type:type}"# No environment variables are required for this skill.
.env
#!/usr/bin/env node
const fs = require('node:fs');
const path = require('node:path');
const target = process.argv[2]
? path.resolve(process.argv[2])
: path.resolve(process.cwd(), 'apps/api/src/plugins/auth.ts');
if (!fs.existsSync(target)) {
console.error(`File not found: ${target}`);
process.exit(1);
}
const source = fs.readFileSync(target, 'utf8');
const checks = [
['web request helper', /function\s+toWebRequest\s*\(/],
['getSession usage', /auth\.api\.getSession/],
['request.user decorator', /decorateRequest\('user'/],
['request.session decorator', /decorateRequest\('session'/],
['request.permissions decorator', /decorateRequest\('permissions'/],
['exclude path handling', /excludePaths|excludeSet/],
['org membership fallback', /org_members|resolveUserOrgMembership/],
];
console.log(`Fastify Better Auth bridge check: ${target}`);
console.log('');
let failures = 0;
for (const [label, pattern] of checks) {
const ok = pattern.test(source);
console.log(`${ok ? '✓' : '✗'} ${label}`);
if (!ok) failures += 1;
}
if (failures > 0) {
console.error('');
console.error(`Bridge check failed with ${failures} missing pattern(s).`);
process.exit(1);
}
console.log('');
console.log('Bridge shape looks complete.');
OCI Cost Management CLI Reference
Cost Analysis
Usage Reports
# List usage reports (requires tenancy-level permissions)
oci usage-api usage-summary request-summarized-usages \
--tenant-id <tenancy-ocid> \
--time-usage-started "2024-01-01T00:00:00Z" \
--time-usage-ended "2024-01-31T23:59:59Z" \
--granularity "DAILY"
# Get usage by service
oci usage-api usage-summary request-summarized-usages \
--tenant-id <tenancy-ocid> \
--time-usage-started "2024-01-01T00:00:00Z" \
--time-usage-ended "2024-01-31T23:59:59Z" \
--granularity "MONTHLY" \
--group-by '["service"]'
# Get usage by compartment
oci usage-api usage-summary request-summarized-usages \
--tenant-id <tenancy-ocid> \
--time-usage-started "2024-01-01T00:00:00Z" \
--time-usage-ended "2024-01-31T23:59:59Z" \
--granularity "MONTHLY" \
--group-by '["compartmentPath"]'
# Get usage by tag
oci usage-api usage-summary request-summarized-usages \
--tenant-id <tenancy-ocid> \
--time-usage-started "2024-01-01T00:00:00Z" \
--time-usage-ended "2024-01-31T23:59:59Z" \
--granularity "MONTHLY" \
--group-by '["tagKey"]' \
--filter '{"operator":"AND","dimensions":[{"key":"tagNamespace","value":"Organization"}]}'Budget Management
Create Budgets
# Create monthly compartment budget
oci budgets budget create \
--compartment-id <compartment-ocid> \
--target-type "COMPARTMENT" \
--targets '["<target-compartment-ocid>"]' \
--amount 10000 \
--reset-period "MONTHLY" \
--display-name "dev-monthly-budget"
# Create tag-based budget
oci budgets budget create \
--compartment-id <tenancy-ocid> \
--target-type "TAG" \
--targets '["Organization.CostCenter.Engineering"]' \
--amount 50000 \
--reset-period "MONTHLY" \
--display-name "engineering-budget"Budget Alerts
# Create budget alert rule (80% threshold)
oci budgets alert-rule create \
--budget-id <budget-ocid> \
--type "ACTUAL" \
--threshold 80 \
--threshold-type "PERCENTAGE" \
--recipients "team@example.com,alerts@example.com" \
--display-name "80-percent-alert"
# Create forecast alert
oci budgets alert-rule create \
--budget-id <budget-ocid> \
--type "FORECAST" \
--threshold 100 \
--threshold-type "PERCENTAGE" \
--recipients "finance@example.com" \
--display-name "forecast-breach-alert"List and Monitor Budgets
# List all budgets
oci budgets budget list --compartment-id <tenancy-ocid> --all
# Get budget status
oci budgets budget get --budget-id <budget-ocid>
# List alert rules for a budget
oci budgets alert-rule list --budget-id <budget-ocid>Service Limits
View Service Limits
# List all service limits
oci limits definition list --compartment-id <tenancy-ocid> --all
# Get specific service limits
oci limits definition list \
--compartment-id <tenancy-ocid> \
--service-name "compute"
# Check limit values
oci limits value list \
--compartment-id <tenancy-ocid> \
--service-name "compute" \
--scope-type "AD" \
--availability-domain <ad-name>
# Check resource availability
oci limits resource-availability get \
--compartment-id <compartment-ocid> \
--service-name "compute" \
--limit-name "vm-standard-e4-flex-core-count" \
--availability-domain <ad-name>Request Limit Increase
# Create limit increase request
oci support incident create \
--compartment-id <tenancy-ocid> \
--csi "<customer-support-identifier>" \
--problem-type "tech" \
--severity "normal" \
--title "Service Limit Increase Request: Compute Cores" \
--description "Request to increase VM.Standard.E4.Flex core count from 100 to 200"Resource Discovery for Cost Optimization
Find Idle Resources
# Find stopped instances (still charged for boot volumes)
oci compute instance list \
--compartment-id <compartment-ocid> \
--lifecycle-state STOPPED \
--query "data[].{Name:\"display-name\",Shape:shape,Created:\"time-created\"}"
# Find unattached block volumes
oci bv volume list \
--compartment-id <compartment-ocid> \
--lifecycle-state AVAILABLE \
--query "data[?!\"volume-attachments\"].{Name:\"display-name\",SizeGB:\"size-in-gbs\"}"
# Find orphaned boot volumes (no instance)
oci bv boot-volume list \
--compartment-id <compartment-ocid> \
--availability-domain <ad-name> \
--query "data[].{Name:\"display-name\",SizeGB:\"size-in-gbs\",State:\"lifecycle-state\"}"Find Over-Provisioned Resources
# Get CPU utilization for instances
oci monitoring metric-data summarize-metrics-data \
--compartment-id <compartment-ocid> \
--namespace "oci_computeagent" \
--query-text 'CpuUtilization[1d].mean()' \
--start-time "$(date -v-7d +%Y-%m-%dT%H:%M:%SZ)" \
--end-time "$(date +%Y-%m-%dT%H:%M:%SZ)"
# Get memory utilization
oci monitoring metric-data summarize-metrics-data \
--compartment-id <compartment-ocid> \
--namespace "oci_computeagent" \
--query-text 'MemoryUtilization[1d].mean()' \
--start-time "$(date -v-7d +%Y-%m-%dT%H:%M:%SZ)" \
--end-time "$(date +%Y-%m-%dT%H:%M:%SZ)"Tagging for Cost Allocation
Create Tag Namespace
# Create tag namespace
oci iam tag-namespace create \
--compartment-id <tenancy-ocid> \
--name "CostAllocation" \
--description "Tags for cost allocation and chargeback"
# Create required tags
oci iam tag create \
--tag-namespace-id <namespace-ocid> \
--name "CostCenter" \
--description "Finance cost center code"
oci iam tag create \
--tag-namespace-id <namespace-ocid> \
--name "Environment" \
--description "Dev/Test/Prod" \
--validator '{"validatorType":"ENUM","values":["Dev","Test","Prod","Sandbox"]}'
oci iam tag create \
--tag-namespace-id <namespace-ocid> \
--name "Owner" \
--description "Team or individual owner"Tag Defaults (Auto-Apply)
# Create tag default for compartment
oci iam tag-default create \
--compartment-id <compartment-ocid> \
--tag-definition-id <tag-definition-ocid> \
--value "Engineering"
# Create dynamic tag default (uses principal name)
oci iam tag-default create \
--compartment-id <compartment-ocid> \
--tag-definition-id <owner-tag-ocid> \
--value "\${iam.principal.name}"Cost Reports (Detailed)
Download Cost Reports
# Cost reports are stored in Object Storage at:
# oci://oci-{tenancy-name}/reports/cost-csv/{date}/
# List available cost reports
oci os object list \
--bucket-name "oci-<tenancy-name>" \
--prefix "reports/cost-csv/"
# Download cost report
oci os object get \
--bucket-name "oci-<tenancy-name>" \
--name "reports/cost-csv/2024-01/cost-report.csv" \
--file cost-report-2024-01.csvCommitted Use Pricing
View Committed Use Discounts
# List subscribed services
oci onesubscription subscription list \
--compartment-id <tenancy-ocid>
# Check commitment utilization
oci onesubscription commitment list \
--compartment-id <tenancy-ocid> \
--subscribed-service-id <service-id>OCI Generative AI Reference
Use this as a current-doc source map for model selection, API usage, and limits.
Official Oracle Sources
- Pretrained foundational models: https://docs.oracle.com/iaas/Content/generative-ai/generate-models.htm
- Generative AI overview: https://docs.oracle.com/iaas/Content/generative-ai/home.htm
- Generative AI service limits: https://docs.oracle.com/iaas/Content/generative-ai/using_limits.htm
- Generative AI Agents: https://docs.oracle.com/iaas/Content/generative-ai-agents/home.htm
- OCI SDK docs: https://docs.oracle.com/en-us/iaas/tools/
Current Hot Words
Command A, Command R, Command R+, Llama, Gemini, Grok, Mistral, gpt-oss, embeddings, rerank, model catalog, RAG, agents, tool use.
Load Guidance
Open the live model catalog before recommending a model, context size, quota, region, or price. Record the date checked in implementation notes.
OCI IAM and Identity Domains Reference
Use this as a source map for OCI IAM policy and identity domain work.
Official Oracle Sources
- IAM overview: https://docs.oracle.com/en-us/iaas/Content/Identity/home.htm
- Common policies: https://docs.oracle.com/en-us/iaas/Content/Identity/Concepts/commonpolicies.htm
- Policy syntax: https://docs.oracle.com/en-us/iaas/Content/Identity/Concepts/policysyntax.htm
- Managing dynamic groups: https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingdynamicgroups.htm
- Identity Domains overview: https://docs.oracle.com/en-us/iaas/Content/Identity/conversion/overview.htm
Load Guidance
Use OCI IAM Identity Domains as current wording. Keep IDCS only as backward-compatible terminology for existing apps and env vars.
OCI Terraform Auth Matrix
Use this reference when Terraform auth is the real problem, especially for 401, 403, NotAuthorizedOrNotFound, or environment-specific failures.
Official Sources
- OCI provider configuration: https://docs.oracle.com/en-us/iaas/Content/terraform/configuring.htm
- Terraform provider registry: https://registry.terraform.io/providers/oracle/oci/latest/docs
- OCI dynamic groups: https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingdynamicgroups.htm
- Resource Manager security: https://docs.oracle.com/en-us/iaas/Content/Security/Reference/resourcemanager_security.htm
- Resource Manager policy reference: https://docs.oracle.com/en-us/iaas/Content/Identity/Reference/resourcemanagerpolicyreference.htm
Context Matrix
| Execution context | Prefer | Avoid |
|---|---|---|
| Local laptop | API key config profile for durable work; SecurityToken profile for short interactive work | Committing private keys, OCIDs, or credentials in provider blocks |
| Cloud Shell | Use current Oracle Cloud Shell/provider guidance and short-lived profile behavior | Assuming a laptop ~/.oci/config exists unchanged |
| GitHub Actions or external CI | Organization-approved OIDC/federation if configured; otherwise scoped API key secret | Long-lived administrator API keys or unscoped tenancy policies |
| OCI DevOps build pipeline | Resource principal/dynamic group policies for the pipeline resource | User credentials copied into build specs |
| OCI Compute instance | auth = "InstancePrincipal" plus dynamic group and IAM policy | API key files on the instance |
| OCI Functions or supported service | auth = "ResourcePrincipal" plus required resource principal env and policies | Instance principal syntax |
| OKE workload | auth = "OKEWorkloadIdentity" when the provider/resource supports it | Node instance principal for app workload identity |
| OCI Resource Manager | Provider block normally needs only region; Resource Manager supplies execution context | Local API key provider blocks inside Resource Manager configs |
Provider Auth Methods
OCI Terraform provider auth methods to check in current docs:
APIKeyInstancePrincipalResourcePrincipalSecurityTokenOKEWorkloadIdentity
When parameters are set in multiple supported provider locations, Oracle documents precedence among environment variables, non-default OCI config profiles, and the DEFAULT profile. Also inspect explicit provider arguments in HCL because they can lock a configuration to the wrong user, tenancy, region, or auth method.
403 Triage
1. Identify the caller: user, group, identity-domain group, dynamic group, CI principal, Resource Manager user/job, instance principal, resource principal, or OKE workload identity. 2. Identify target resource family and compartment. 3. Check policy location is at or above the target resource compartment. 4. Check verb is high enough: inspect < read < use < manage. 5. Check resource family is correct: virtual-network-family, instance-family, volume-family, object-family, orm-family, etc. 6. Check condition clauses and dynamic-group matching rules. 7. Allow for IAM propagation lag before rerunning.
Pressure Scenarios
- "Terraform apply gets 403 creating a VCN": verify caller and
manage virtual-network-familyscope before changing HCL. - "Compute instance Terraform cannot list buckets": use instance principal dynamic-group membership and
object-familypolicy. - "Resource Manager cannot create a stack from Git": check
orm-config-source-providers,orm-stacks, and source provider permissions. - "IDCS group can log in but Terraform fails": map identity-domain/IDCS group membership to the OCI IAM policy subject and compartment scope.
OCI Terraform Bastion Automation
Use this reference when Terraform manages OCI Bastion resources, sessions, allowlists, IAM, or private-access guardrails.
Official Sources
- Bastion overview: https://docs.oracle.com/iaas/Content/Bastion/Concepts/bastionoverview.htm
- Creating a Managed SSH session: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/create-session-managed-ssh.htm
- Connecting to port forwarding: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/connect-port-forwarding.htm
- Bastion IAM policies: https://docs.oracle.com/en-us/iaas/Content/Bastion/Reference/bastionpolicyreference.htm
- Bastion known issues: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/known-issues.htm
- OCI Terraform provider docs: https://registry.terraform.io/providers/oracle/oci/latest/docs
Behavioral Rules
- Prefer OCI Bastion or private connectivity over public SSH for private instance access.
- Treat client CIDR allowlists as sensitive operational controls. Avoid permanent
0.0.0.0/0. - Do not store private keys in Terraform state. Use external key generation and controlled distribution.
- Use Managed SSH only when the target supports Oracle Cloud Agent and Bastion plugin requirements.
- Use port forwarding for unsupported targets, database listeners, RDP, ADB private endpoints, or Managed SSH plugin gaps.
- Treat sessions as ephemeral access objects; clean them up unless the operating model explicitly keeps them.
Terraform Review Checklist
- Does the plan create or widen a client CIDR allowlist?
- Does the plan create public IPs or public SSH rules as a shortcut?
- Are session TTLs within Oracle's current 30-to-180-minute bounds?
- Are target-side NSGs/security lists scoped to the bastion path and target port?
- Are IAM policies scoped to bastion/session operations and target resource needs?
- Are SSH public keys inputs and private keys kept out of state?
- Does the target image/shape require port forwarding instead of Managed SSH?
Allowlist Safety
For Terraform-managed allowlists, do not make ad hoc Console changes without reconciling state. For emergency access, prefer a short-lived, reviewed variable change with cleanup, or use CLI/Console with an explicit post-incident import/state reconciliation step.
Pressure Scenario
"Terraform should create a Bastion for private instance access."
Passing answer: create OCI Bastion with narrow allowlists, target-side network rules, scoped IAM, no public SSH fallback, no private keys in state, and explicit session cleanup behavior.
OCI Terraform Import, Drift, and Adoption
Use this reference when adopting existing OCI resources, repairing state, or diagnosing provider drift.
Official Sources
- Terraform import command: https://developer.hashicorp.com/terraform/cli/commands/import
- Terraform import blocks: https://developer.hashicorp.com/terraform/language/import
- Terraform moved blocks: https://developer.hashicorp.com/terraform/language/modules/develop/refactoring
- OCI Terraform provider: https://registry.terraform.io/providers/oracle/oci/latest/docs
- Resource Manager import state job: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Concepts/resource-manager-and-terraform.htm
Adoption Flow
1. Pin Terraform and oracle/oci provider versions before import. 2. Back up current state or confirm remote state versioning. 3. Write the intended HCL first, matching the real resource shape. 4. Get the official import ID format from the exact provider resource documentation. 5. Import one resource at a time. 6. Run terraform plan after each import and reconcile computed/default fields. 7. Use moved blocks for address changes after adoption. 8. Use ignore_changes only for explicitly console-owned fields, commonly tags, and document the owner.
OCI-Specific Drift Patterns
- Eventual consistency can make freshly created IAM, networking, and database resources appear missing. Prefer provider timeouts/retries and staged applies over blind retries.
- Some resource IDs are simple OCIDs; others are composite IDs. Always check the provider resource page.
- Identity resources often live at tenancy/root scope even when the workload lives in a compartment.
- Tags, defined tags, default security lists, route rules, and generated names often create noisy drift.
- Provider upgrades can change computed fields; read changelogs before relaxing lifecycle rules.
Resource Manager Adoption
Use Resource Manager import-state jobs when moving a local Terraform environment into Resource Manager. Do not copy .terraform/, local state files, or local backend credentials into a Resource Manager stack zip.
Pressure Scenarios
- "Import this existing VCN": get the provider import ID, write matching HCL, import, then plan.
- "Terraform wants to replace a subnet": check immutable fields, route/security-list associations, provider version drift, and moved blocks before accepting replacement.
- "Provider schema validation fails locally on darwin_arm64": treat known OCI provider plugin startup failures as environment blockers until confirmed, not as HCL proof.
OCI Terraform Module Quality Checklist
Use this reference before recommending official or community Terraform modules for OCI.
Official Sources
- Terraform module sources: https://developer.hashicorp.com/terraform/language/modules/sources
- Terraform provider dependency lock file: https://developer.hashicorp.com/terraform/language/files/dependency-lock
- Oracle Terraform provider examples: https://github.com/oracle/terraform-provider-oci/tree/master/examples
- Oracle Terraform modules organization: https://github.com/oracle-terraform-modules
Checklist
Review every module, including Oracle-branded modules, against these criteria:
| Check | Passing signal |
|---|---|
| Release freshness | Recent release or commit compatible with current OCI provider behavior |
| Provider constraints | Explicit oracle/oci provider source and version range that fits the target Terraform version |
| Terraform version | Compatible with the target CLI and Resource Manager supported versions |
| Examples | Examples cover the target use case, not only a toy happy path |
| Issues and PRs | Open issues do not show unresolved provider drift or broken resources |
| Supported resources | Module supports required OCI features, regions, realms, and new service options |
| State shape | Outputs are stable, sensitive outputs are minimized, and module addresses are acceptable |
| Brownfield adoption | Module can import/adopt existing resources without replacement surprises |
| Security | Least-privilege IAM, no broad admin defaults, no secret content outputs |
| Upgrade path | Changelog explains breaking changes and migration steps |
When to Avoid a Module
- The module pins an old provider or references deprecated provider source addresses.
- The module hides resource addresses that need precise import or moved-block control.
- The module creates broad IAM, networking, or tagging defaults that conflict with tenant governance.
- The module has no clear support for the target realm, region, identity-domain model, or Resource Manager runtime.
- The module adds more abstraction than the workload needs.
Recommendation Pattern
When recommending a module, include:
1. Module name and exact version/ref. 2. Provider and Terraform version constraints. 3. Last release or commit date checked. 4. Known gaps and resources still written directly. 5. Import and state migration impact. 6. A minimal plan-review gate before apply.
Pressure Scenario
User asks: "Can we use the official OCI landing zone module?"
Passing answer: do not answer yes because it is official. Check release recency, provider constraints, brownfield risk, examples, issue activity, generated plan, and whether oci/landing-zones should own the architecture decision.
OCI Terraform and Resource Manager Reference
Use this as a source map for OCI IaC work.
Official Oracle Sources
- Terraform with OCI: https://docs.oracle.com/en-us/iaas/Content/dev/terraform/home.htm
- Object Storage backend for Terraform state: https://docs.oracle.com/en-us/iaas/Content/terraform/object-storage-state.htm
- Resource Manager overview: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Concepts/resourcemanager.htm
- OCI Terraform provider: https://registry.terraform.io/providers/oracle/oci/latest/docs
- OCI Resource Manager stacks: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Tasks/create-stack.htm
- OCI provider configuration: https://docs.oracle.com/en-us/iaas/Content/terraform/configuring.htm
- Resource Manager and Terraform: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Concepts/resource-manager-and-terraform.htm
- Terraform sensitive data: https://developer.hashicorp.com/terraform/language/manage-sensitive-data
Load Guidance
For Terraform v1.12+, prefer the native OCI backend for Object Storage state. Treat S3-compatible Object Storage state as deprecated fallback unless the target environment cannot use the native backend.
Use the focused sibling references first:
oci-terraform-state-backends.mdfor backend and state-locking choices.oci-terraform-auth-matrix.mdfor caller/auth troubleshooting.oci-terraform-secrets-state.mdfor Vault, passwords, wallets, keys, and outputs.oci-terraform-import-drift.mdfor brownfield adoption.oci-terraform-module-quality.mdfor official-module review.oci-terraform-realms-regions.mdfor government, FIPS, realm, and endpoint checks.oci-terraform-zpr.mdfor ZPR security attributes, policy sequencing, provider support, imports, and rollout safety.oci-terraform-bastion.mdfor Bastion resources, sessions, allowlists, IAM, key-state safety, and no-public-SSH guardrails.
OCI Terraform Realms, Regions, and Government Guardrails
Use this reference when Terraform targets OCI regions beyond the default commercial assumptions.
Official Sources
- OCI regions and availability domains: https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm
- OCI provider configuration and dedicated endpoints: https://docs.oracle.com/en-us/iaas/Content/terraform/configuring.htm
- Terraform provider home: https://docs.oracle.com/en-us/iaas/Content/terraform/home.htm
- Resource Manager overview and FIPS note: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Concepts/resourcemanager.htm
Guardrails
- Verify the region identifier, realm, and availability-domain names from the target tenancy. AD names are tenancy-specific.
- Do not hardcode
oraclecloud.comendpoint assumptions. Dedicated, government, and sovereign-style environments may need realm-specific endpoints. - For Object Storage dedicated endpoints, check
realm_specific_service_endpoint_template_enabledor the matching environment variable in current provider docs. - For US Government Cloud or US Defense Cloud, verify whether the FIPS-compatible OCI Terraform provider is required.
- Confirm the target service is available in the target region before writing resources.
- Confirm Resource Manager is available in the target region/realm before choosing it as the execution control plane.
- Avoid copying commercial-region examples into government or dedicated environments without endpoint, service, and provider checks.
Region Review Checklist
1. Region identifier and realm. 2. Tenancy Object Storage namespace. 3. Service availability for every resource type. 4. Provider endpoint or dedicated endpoint settings. 5. FIPS/provider requirement. 6. Resource Manager availability and supported Terraform/provider versions. 7. Quotas and service limits in the exact region and compartment. 8. Data residency, logging, and replication constraints.
Pressure Scenario
User asks: "Write Terraform for OCI government cloud."
Passing answer: pause to verify realm, region, service availability, FIPS-compatible provider guidance, dedicated endpoint settings, and Resource Manager availability before writing commercial-region HCL.
OCI Terraform Secrets and State Safety
Use this reference when Terraform interacts with OCI Vault, passwords, wallets, private keys, generated secrets, stack variables, or sensitive outputs.
Official Sources
- Terraform sensitive data: https://developer.hashicorp.com/terraform/language/manage-sensitive-data
- Terraform OCI backend credential warning: https://developer.hashicorp.com/terraform/language/backend/oci
- OCI provider configuration: https://docs.oracle.com/en-us/iaas/Content/terraform/configuring.htm
- OCI Vault and secrets: https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Concepts/keyoverview.htm
- Resource Manager configuration requirements: https://docs.oracle.com/en-us/iaas/Content/ResourceManager/Concepts/terraformconfigresourcemanager.htm
Core Rule
Terraform state and plan files can contain sensitive values. sensitive = true hides values in CLI/UI output but still stores values in state unless Terraform ephemeral/write-only behavior is supported in that exact context.
High-Risk Values
Avoid putting these in Terraform state:
- Database admin passwords and generated passwords.
- ADB wallets, wallet passwords, and connection strings with credentials.
- Private keys, SSH keys, API signing keys, and customer secret keys.
- Secret contents read from OCI Vault or supplied as variables.
- User data or cloud-init that embeds credentials.
- Sensitive root-module outputs consumed by
terraform_remote_state.
Safer Patterns
- Store and rotate secret material in OCI Vault; Terraform should usually manage vault/key/secret metadata and pass secret OCIDs, not secret contents.
- Let applications retrieve secrets at runtime through instance principals, resource principals, or workload identity.
- Use generated secret/password features outside Terraform state when supported by OCI service workflows.
- Use
sensitive = trueto reduce accidental display, but still protect backend state as secret material. - Use Terraform
ephemeralvariables or write-only arguments only after verifying Terraform version and OCI provider/resource support. - For Resource Manager, do not put user credentials or confidential values in Terraform configuration files. Treat stack variables, job logs, config zips, plans, and state as sensitive review surfaces.
State Review Checklist
Before approving Terraform that touches secrets:
1. Run terraform plan and inspect which attributes are written. 2. Search for random_password, tls_private_key, oci_vault_secret, wallet files, private_key, password, and sensitive outputs. 3. Check whether any data source reads actual secret content. 4. Confirm state backend access is least-privilege and versioned. 5. Confirm outputs do not expose values to terraform_remote_state consumers. 6. Document any unavoidable state exposure and the rotation/remediation plan.
Pressure Scenario
User asks: "Use Vault for the DB password in Terraform."
Passing answer: explain that Vault alone does not prevent Terraform state capture, prefer runtime retrieval or secret OCID references, and only use Terraform-managed secret content if state exposure is explicitly accepted and protected.
OCI Terraform State Backends
Use this reference when deciding where Terraform state lives for OCI work.
Official Sources
- Terraform native OCI backend: https://developer.hashicorp.com/terraform/language/backend/oci
- Terraform backend configuration: https://developer.hashicorp.com/terraform/language/backend
- Terraform sensitive data: https://developer.hashicorp.com/terraform/language/manage-sensitive-data
- Oracle Terraform provider: https://docs.oracle.com/en-us/iaas/Content/terraform/home.htm
- Oracle Object Storage state legacy path: https://docs.oracle.com/en-us/iaas/Content/terraform/object-storage-state.htm
Decision Tree
| Situation | Backend choice |
|---|---|
| Terraform v1.12+ and OCI Object Storage allowed | Prefer native backend "oci" |
| OCI Resource Manager stack | Let Resource Manager manage stack state |
| Terraform older than v1.12 or incompatible runtime | S3-compatible Object Storage fallback, explicitly marked legacy |
| One-person disposable experiment | Local state is acceptable only if no team or production resources are managed |
| HCP Terraform/Terraform Enterprise is the chosen control plane | Use that product's remote state model, not OCI Object Storage by default |
Native OCI Backend Baseline
terraform {
backend "oci" {
bucket = "terraform-state"
namespace = "object-storage-namespace"
key = "prod/network/terraform.tfstate"
region = "us-ashburn-1"
}
}Add optional workspace_key_prefix for workspace separation and kms_key_id when a specific OCI KMS key is required. Prefer partial backend configuration and environment/config-file credentials rather than embedding secrets in HCL.
Safety Rules
- Enable Object Storage bucket versioning for state recovery.
- Grant the state principal only the bucket/object operations needed for state and lock objects.
- Treat state, lock files, plan files, and
.terraform/as sensitive. - Do not pass plaintext credentials through
-backend-config; Terraform can persist backend configuration under.terraform/and in saved plans. - Do not use customer secret keys for new Terraform v1.12+ state unless a legacy fallback is explicitly required and documented.
- Separate state by environment and blast radius: tenancy/bootstrap, networking, security, workloads, and databases should not all share one state file.
Legacy S3-Compatible Fallback
Use only when the runtime cannot use native backend "oci". Document:
1. Terraform/OpenTofu version and why native OCI backend is unavailable. 2. Customer secret key owner and rotation procedure. 3. Bucket versioning, encryption, and lifecycle policy. 4. Locking limitations and concurrent apply control. 5. Migration path back to native backend "oci".
Pressure Scenario
User asks: "Set up Terraform state in OCI Object Storage for Terraform 1.12."
Passing answer: choose native backend "oci", enable bucket versioning, avoid hardcoded credentials, and mention S3-compatible Object Storage only as a legacy fallback.
OCI Terraform ZPR Automation
Use this reference when Terraform manages Zero Trust Packet Routing (ZPR) enablement, security attributes, ZPR policy, or protected-resource rollout.
Official Sources
- ZPR overview: https://docs.oracle.com/en-us/iaas/Content/zero-trust-packet-routing/overview.htm
- Enabling ZPR: https://docs.oracle.com/en-us/iaas/Content/zero-trust-packet-routing/enable-zpr.htm
- Security attributes: https://docs.oracle.com/en-us/iaas/Content/zero-trust-packet-routing/security-attributes.htm
- ZPR policy overview: https://docs.oracle.com/iaas/Content/zero-trust-packet-routing/zpr-policy-overview.htm
- OCI Terraform provider docs: https://registry.terraform.io/providers/oracle/oci/latest/docs
Behavioral Rules
- Check current provider support before writing ZPR resources; ZPR support is newer than many examples and modules.
- Sequence policy before attributes. Applying attributes before allow policy can block production flows.
- Treat resource import/adoption as a first-class step for existing namespaces, policies, VCNs, VNICs, databases, and private endpoints.
- Review the plan for large attribute fan-out. A single attribute change can affect multiple flows.
- Keep rollback simple: remove the attribute or correct the ZPL policy before broad network rewrites.
- Do not assume ZPR replaces route tables, NSGs, or security lists.
Lockout-Safe Apply Sequence
1. Pin Terraform and OCI provider versions. 2. Import or data-source existing namespaces, attributes, policies, and target resources. 3. Add ZPL policy that permits known-good source-to-target flows. 4. Plan and peer-review the policy diff. 5. Apply policy only. 6. Apply attributes to a non-production or canary resource. 7. Validate connectivity and observability. 8. Expand attributes in small batches.
Plan Review Checklist
- Does the provider version support every ZPR resource or attribute field used?
- Does the plan create policy before assigning attributes?
- Does the plan touch production resources, VNICs, databases, private endpoints, or VCN attributes?
- Are route tables, NSGs, security lists, and DNS unchanged unless intentionally reviewed?
- Are imports and moved blocks used instead of delete/recreate for brownfield ZPR?
- Is there a rollback command or targeted revert path?
Pressure Scenario
"Terraform should add ZPR attributes to production resources."
Passing answer: stop and require policy-first sequencing, provider support check, import/adoption review, canary rollout, and rollback before applying attributes broadly.
OCI CLI for Landing Zone Operations
Complete OCI CLI commands for deploying and managing landing zones.
Prerequisites
# Verify OCI CLI and authentication
oci --version
oci iam region list --output table
# Get tenancy OCID (needed for root compartment operations)
export TENANCY_ID=$(oci iam compartment list --all \
--compartment-id-in-subtree true \
--access-level ACCESSIBLE \
--include-root \
--query "data[?name=='root'].id | [0]" \
--raw-output)
echo "Tenancy ID: $TENANCY_ID"Compartment Management
Create Compartment Hierarchy
# 1. Create top-level compartments
NETWORK_CMP=$(oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Network" \
--description "Network resources and topology" \
--query 'data.id' --raw-output)
SECURITY_CMP=$(oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Security" \
--description "Security services" \
--query 'data.id' --raw-output)
WORKLOADS_CMP=$(oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Workloads" \
--description "Application workloads" \
--query 'data.id' --raw-output)
SHARED_CMP=$(oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Shared-Services" \
--description "Shared platform services" \
--query 'data.id' --raw-output)
# 2. Create Network sub-compartments
HUB_CMP=$(oci iam compartment create \
--compartment-id $NETWORK_CMP \
--name "Hub" \
--description "Hub VCN for centralized services" \
--query 'data.id' --raw-output)
SPOKES_CMP=$(oci iam compartment create \
--compartment-id $NETWORK_CMP \
--name "Spokes" \
--description "Spoke VCNs for workloads" \
--query 'data.id' --raw-output)
# 3. Create Workload compartments
APP1_CMP=$(oci iam compartment create \
--compartment-id $WORKLOADS_CMP \
--name "App1" \
--description "Application 1" \
--query 'data.id' --raw-output)
# 4. Create environment compartments under App1
APP1_DEV_CMP=$(oci iam compartment create \
--compartment-id $APP1_CMP \
--name "Dev" \
--description "Development environment" \
--query 'data.id' --raw-output)
APP1_TEST_CMP=$(oci iam compartment create \
--compartment-id $APP1_CMP \
--name "Test" \
--description "Test environment" \
--query 'data.id' --raw-output)
APP1_PROD_CMP=$(oci iam compartment create \
--compartment-id $APP1_CMP \
--name "Prod" \
--description "Production environment" \
--query 'data.id' --raw-output)List Compartment Hierarchy
# List all compartments with hierarchy
oci iam compartment list \
--compartment-id $TENANCY_ID \
--compartment-id-in-subtree true \
--access-level ACCESSIBLE \
--all \
--output table
# Get compartment OCID by name
oci iam compartment list \
--compartment-id $TENANCY_ID \
--name "Prod" \
--compartment-id-in-subtree true \
--query 'data[0].id' \
--raw-outputMove Resources Between Compartments
# Move compute instance to different compartment
oci compute instance change-compartment \
--instance-id ocid1.instance.oc1..xxx \
--compartment-id $APP1_PROD_CMP
# Move VCN to different compartment
oci network vcn change-compartment \
--vcn-id ocid1.vcn.oc1..xxx \
--compartment-id $NETWORK_CMPTag Namespace and Defaults
Create Tag Namespace
# Create organization tag namespace
TAG_NAMESPACE=$(oci iam tag-namespace create \
--compartment-id $TENANCY_ID \
--name "Organization" \
--description "Organization-wide required tags" \
--query 'data.id' --raw-output)
echo "Tag Namespace ID: $TAG_NAMESPACE"Create Tag Definitions
# CostCenter tag (mandatory)
COSTCENTER_TAG=$(oci iam tag create \
--tag-namespace-id $TAG_NAMESPACE \
--name "CostCenter" \
--description "Cost center for chargeback" \
--is-retired false \
--query 'data.id' --raw-output)
# Environment tag (mandatory, enum)
ENVIRONMENT_TAG=$(oci iam tag create \
--tag-namespace-id $TAG_NAMESPACE \
--name "Environment" \
--description "Environment type" \
--is-retired false \
--validator '{
"validatorType": "ENUM",
"values": ["Dev", "Test", "Prod", "Sandbox"]
}' \
--query 'data.id' --raw-output)
# Owner tag (mandatory)
OWNER_TAG=$(oci iam tag create \
--tag-namespace-id $TAG_NAMESPACE \
--name "Owner" \
--description "Resource owner email or team" \
--is-retired false \
--query 'data.id' --raw-output)
# DataClassification tag
DATACLASS_TAG=$(oci iam tag create \
--tag-namespace-id $TAG_NAMESPACE \
--name "DataClassification" \
--description "Data sensitivity classification" \
--is-retired false \
--validator '{
"validatorType": "ENUM",
"values": ["Public", "Internal", "Confidential", "Restricted"]
}' \
--query 'data.id' --raw-output)
# BackupPolicy tag
BACKUP_TAG=$(oci iam tag create \
--tag-namespace-id $TAG_NAMESPACE \
--name "BackupPolicy" \
--description "Backup retention policy" \
--is-retired false \
--validator '{
"validatorType": "ENUM",
"values": ["None", "Bronze", "Silver", "Gold"]
}' \
--query 'data.id' --raw-output)Set Tag Defaults (Auto-apply Tags)
# Make Environment=Prod default in Prod compartment
oci iam tag-default create \
--compartment-id $APP1_PROD_CMP \
--tag-definition-id $ENVIRONMENT_TAG \
--value "Prod"
# Make Environment=Dev default in Dev compartment
oci iam tag-default create \
--compartment-id $APP1_DEV_CMP \
--tag-definition-id $ENVIRONMENT_TAG \
--value "Dev"
# Make Owner default to creator's username
oci iam tag-default create \
--compartment-id $WORKLOADS_CMP \
--tag-definition-id $OWNER_TAG \
--value "\${iam.principal.name}"
# Make DataClassification=Internal default
oci iam tag-default create \
--compartment-id $WORKLOADS_CMP \
--tag-definition-id $DATACLASS_TAG \
--value "Internal"List Tags
# List all tag namespaces
oci iam tag-namespace list \
--compartment-id $TENANCY_ID \
--all \
--output table
# List tags in namespace
oci iam tag list \
--tag-namespace-id $TAG_NAMESPACE \
--all \
--output tableSecurity Zones
Create Security Zone Recipe
# Create CIS Foundation recipe
CIS_RECIPE=$(oci cloud-guard security-zone-recipe create \
--compartment-id $TENANCY_ID \
--display-name "CIS-Foundation-Recipe" \
--description "CIS OCI Foundations Benchmark security policies" \
--security-policies '["deny-public-ip-on-compute", "deny-public-bucket", "require-boot-volume-backup", "require-block-volume-backup"]' \
--query 'data.id' --raw-output)
# Create production-specific recipe (stricter)
PROD_RECIPE=$(oci cloud-guard security-zone-recipe create \
--compartment-id $TENANCY_ID \
--display-name "Production-Recipe" \
--description "Production security requirements" \
--security-policies '["deny-public-ip-on-compute", "deny-public-bucket", "deny-public-lb", "require-encryption-at-rest", "require-encryption-in-transit", "require-boot-volume-backup", "require-block-volume-backup", "deny-internet-gateway-in-private-subnet"]' \
--query 'data.id' --raw-output)Apply Security Zone to Compartment
# Apply production recipe to prod compartment
oci cloud-guard security-zone create \
--compartment-id $APP1_PROD_CMP \
--display-name "App1-Prod-Security-Zone" \
--description "Security zone for App1 production" \
--security-zone-recipe-id $PROD_RECIPE
# Apply CIS recipe to test compartment
oci cloud-guard security-zone create \
--compartment-id $APP1_TEST_CMP \
--display-name "App1-Test-Security-Zone" \
--description "Security zone for App1 test" \
--security-zone-recipe-id $CIS_RECIPEList Security Zones
# List all security zones
oci cloud-guard security-zone list \
--compartment-id $TENANCY_ID \
--compartment-id-in-subtree true \
--all \
--output table
# Get security zone details
oci cloud-guard security-zone get \
--security-zone-id ocid1.securityzone.oc1..xxxCloud Guard Configuration
Enable Cloud Guard
# Enable Cloud Guard for tenancy
oci cloud-guard configuration update \
--reporting-region us-ashburn-1 \
--status ENABLED \
--self-manage-resources true
# Check Cloud Guard status
oci cloud-guard configuration getCreate Cloud Guard Target
# Create target for workloads compartment
CLOUDGUARD_TARGET=$(oci cloud-guard target create \
--compartment-id $TENANCY_ID \
--display-name "Workloads-Target" \
--description "Cloud Guard monitoring for all workloads" \
--target-resource-type COMPARTMENT \
--target-resource-id $WORKLOADS_CMP \
--target-detector-recipes '[
{
"detectorRecipeId": "ocid1.cloudguarddetectorrecipe.oc1..configuration",
"detector": "IAAS_CONFIGURATION_DETECTOR"
},
{
"detectorRecipeId": "ocid1.cloudguarddetectorrecipe.oc1..activity",
"detector": "IAAS_ACTIVITY_DETECTOR"
}
]' \
--query 'data.id' --raw-output)List Cloud Guard Problems
# List all open problems
oci cloud-guard problem list \
--compartment-id $TENANCY_ID \
--compartment-id-in-subtree true \
--lifecycle-state OPEN \
--output table
# List problems by risk level
oci cloud-guard problem list \
--compartment-id $WORKLOADS_CMP \
--risk-level CRITICAL \
--output tableBudget Management
Create Budget for Compartment
# Create monthly budget for production
PROD_BUDGET=$(oci budgets budget create \
--compartment-id $TENANCY_ID \
--amount 25000 \
--reset-period MONTHLY \
--target-type COMPARTMENT \
--targets "[$APP1_PROD_CMP]" \
--display-name "App1-Prod-Monthly-Budget" \
--description "Production environment monthly budget: \$25,000" \
--query 'data.id' --raw-output)
# Create budget for dev environment (lower threshold)
DEV_BUDGET=$(oci budgets budget create \
--compartment-id $TENANCY_ID \
--amount 5000 \
--reset-period MONTHLY \
--target-type COMPARTMENT \
--targets "[$APP1_DEV_CMP]" \
--display-name "App1-Dev-Monthly-Budget" \
--description "Dev environment monthly budget: \$5,000" \
--query 'data.id' --raw-output)
# Create budget for tags (cost center-based)
oci budgets budget create \
--compartment-id $TENANCY_ID \
--amount 50000 \
--reset-period MONTHLY \
--target-type TAG \
--targets '["Organization.CostCenter=Engineering"]' \
--display-name "Engineering-CostCenter-Budget" \
--description "Engineering cost center budget: \$50,000"Create Budget Alert Rules
# Alert at 50% threshold
oci budgets alert-rule create \
--budget-id $PROD_BUDGET \
--type ACTUAL \
--threshold 50 \
--threshold-type PERCENTAGE \
--display-name "Prod-50%-Warning" \
--message "Production budget at 50% (\$12,500)" \
--recipients "sre-team@example.com"
# Alert at 80% threshold
oci budgets alert-rule create \
--budget-id $PROD_BUDGET \
--type ACTUAL \
--threshold 80 \
--threshold-type PERCENTAGE \
--display-name "Prod-80%-Critical" \
--message "Production budget at 80% (\$20,000) - CRITICAL" \
--recipients "sre-team@example.com,cfo@example.com"
# Alert at 100% threshold
oci budgets alert-rule create \
--budget-id $PROD_BUDGET \
--type ACTUAL \
--threshold 100 \
--threshold-type PERCENTAGE \
--display-name "Prod-100%-Exceeded" \
--message "Production budget EXCEEDED (\$25,000)" \
--recipients "sre-team@example.com,cfo@example.com,ceo@example.com"
# Forecast alert (predict 100% in current month)
oci budgets alert-rule create \
--budget-id $PROD_BUDGET \
--type FORECAST \
--threshold 100 \
--threshold-type PERCENTAGE \
--display-name "Prod-Forecast-100%" \
--message "Production forecasted to exceed budget this month" \
--recipients "sre-team@example.com"List Budgets
# List all budgets
oci budgets budget list \
--compartment-id $TENANCY_ID \
--target-type COMPARTMENT \
--output table
# Get budget utilization
oci budgets budget get \
--budget-id $PROD_BUDGETHub-Spoke Network Topology
Create Hub VCN
# Create Hub VCN in Hub compartment
HUB_VCN=$(oci network vcn create \
--compartment-id $HUB_CMP \
--display-name "Hub-VCN" \
--cidr-blocks '["10.0.0.0/16"]' \
--dns-label "hub" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Create Hub subnets
HUB_PUBLIC_SUBNET=$(oci network subnet create \
--compartment-id $HUB_CMP \
--vcn-id $HUB_VCN \
--display-name "Hub-Public-Subnet" \
--cidr-block "10.0.1.0/24" \
--prohibit-public-ip-on-vnic false \
--dns-label "hubpub" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
HUB_PRIVATE_SUBNET=$(oci network subnet create \
--compartment-id $HUB_CMP \
--vcn-id $HUB_VCN \
--display-name "Hub-Private-Subnet" \
--cidr-block "10.0.2.0/24" \
--prohibit-public-ip-on-vnic true \
--dns-label "hubpriv" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)Create DRG (Dynamic Routing Gateway)
# Create DRG for hub-spoke connectivity
DRG=$(oci network drg create \
--compartment-id $NETWORK_CMP \
--display-name "Hub-Spoke-DRG" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Attach Hub VCN to DRG
HUB_DRG_ATTACHMENT=$(oci network drg-attachment create \
--drg-id $DRG \
--display-name "Hub-VCN-Attachment" \
--vcn-id $HUB_VCN \
--wait-for-state ATTACHED \
--query 'data.id' --raw-output)Create Spoke VCNs
# Create Spoke VCN for App1 Prod
SPOKE1_VCN=$(oci network vcn create \
--compartment-id $SPOKES_CMP \
--display-name "Spoke-App1-Prod-VCN" \
--cidr-blocks '["10.10.0.0/16"]' \
--dns-label "app1prod" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Attach Spoke1 to DRG
SPOKE1_DRG_ATTACHMENT=$(oci network drg-attachment create \
--drg-id $DRG \
--display-name "Spoke-App1-Prod-Attachment" \
--vcn-id $SPOKE1_VCN \
--wait-for-state ATTACHED \
--query 'data.id' --raw-output)
# Create Spoke VCN for App1 Dev
SPOKE2_VCN=$(oci network vcn create \
--compartment-id $SPOKES_CMP \
--display-name "Spoke-App1-Dev-VCN" \
--cidr-blocks '["10.11.0.0/16"]' \
--dns-label "app1dev" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Attach Spoke2 to DRG
SPOKE2_DRG_ATTACHMENT=$(oci network drg-attachment create \
--drg-id $DRG \
--display-name "Spoke-App1-Dev-Attachment" \
--vcn-id $SPOKE2_VCN \
--wait-for-state ATTACHED \
--query 'data.id' --raw-output)Configure Hub NAT Gateway (Shared Egress)
# Create NAT Gateway in Hub VCN
HUB_NAT=$(oci network nat-gateway create \
--compartment-id $HUB_CMP \
--vcn-id $HUB_VCN \
--display-name "Hub-NAT-Gateway" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Create Service Gateway in Hub VCN (free egress to OCI services)
HUB_SGW=$(oci network service-gateway create \
--compartment-id $HUB_CMP \
--vcn-id $HUB_VCN \
--services '[{"serviceId": "ocid1.service.oc1.iad.xxx"}]' \
--display-name "Hub-Service-Gateway" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Get default route table for Hub VCN
HUB_RT=$(oci network vcn get \
--vcn-id $HUB_VCN \
--query 'data["default-route-table-id"]' \
--raw-output)
# Add route to NAT Gateway for internet egress
oci network route-table update \
--rt-id $HUB_RT \
--route-rules '[
{
"destination": "0.0.0.0/0",
"destinationType": "CIDR_BLOCK",
"networkEntityId": "'$HUB_NAT'"
},
{
"destination": "all-iad-services-in-oracle-services-network",
"destinationType": "SERVICE_CIDR_BLOCK",
"networkEntityId": "'$HUB_SGW'"
}
]' \
--forceConfigure DRG Route Tables (Spoke-to-Hub Routing)
# Get DRG route table ID
DRG_RT=$(oci network drg list-drg-route-tables \
--drg-id $DRG \
--query 'data[0].id' \
--raw-output)
# Add route distribution to allow spokes to reach hub
oci network drg-route-distribution create \
--drg-id $DRG \
--distribution-type IMPORT \
--display-name "Import-All-VCN-Routes"Resource Manager Stacks
Upload Landing Zone Terraform Configuration
# Create ZIP file with Terraform configs
cd landing-zone-terraform/
zip -r ../landing-zone.zip ./*
cd ..
# Create Resource Manager stack
STACK=$(oci resource-manager stack create \
--compartment-id $TENANCY_ID \
--display-name "OCI-Landing-Zone-Stack" \
--description "Complete landing zone deployment" \
--config-source-type ZIP_UPLOAD \
--zip-file-base64 "$(base64 landing-zone.zip)" \
--variables '{
"tenancy_ocid": "'$TENANCY_ID'",
"region": "us-ashburn-1",
"compartment_hierarchy": true,
"security_zones_enabled": true,
"hub_spoke_topology": true
}' \
--wait-for-state SUCCEEDED \
--query 'data.id' --raw-output)
# Plan the stack
PLAN_JOB=$(oci resource-manager job create-plan-job \
--stack-id $STACK \
--wait-for-state SUCCEEDED \
--query 'data.id' --raw-output)
# Apply the stack
APPLY_JOB=$(oci resource-manager job create-apply-job \
--stack-id $STACK \
--execution-plan-strategy AUTO_APPROVED \
--wait-for-state SUCCEEDED \
--query 'data.id' --raw-output)
# Get outputs
oci resource-manager stack get-stack-tf-state \
--stack-id $STACK \
--file stack-outputs.tfstateMulti-Region Setup
Create DR Region Landing Zone
# Set DR region
export OCI_CLI_REGION=us-phoenix-1
# Create same compartment hierarchy in DR region
# (Compartments are global, but resources are regional)
# Create DR Hub VCN
DR_HUB_VCN=$(oci network vcn create \
--compartment-id $HUB_CMP \
--display-name "Hub-VCN-DR" \
--cidr-blocks '["10.100.0.0/16"]' \
--dns-label "hubdr" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Create DR DRG
DR_DRG=$(oci network drg create \
--compartment-id $NETWORK_CMP \
--display-name "Hub-Spoke-DRG-DR" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Create Remote Peering Connection (primary to DR)
export OCI_CLI_REGION=us-ashburn-1
PRIMARY_RPC=$(oci network remote-peering-connection create \
--compartment-id $NETWORK_CMP \
--drg-id $DRG \
--display-name "Primary-to-DR-RPC" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
export OCI_CLI_REGION=us-phoenix-1
DR_RPC=$(oci network remote-peering-connection create \
--compartment-id $NETWORK_CMP \
--drg-id $DR_DRG \
--display-name "DR-to-Primary-RPC" \
--wait-for-state AVAILABLE \
--query 'data.id' --raw-output)
# Connect the peering
oci network remote-peering-connection connect \
--remote-peering-connection-id $DR_RPC \
--peer-id $PRIMARY_RPC \
--peer-region-name us-ashburn-1Validation and Reporting
List All Landing Zone Resources
# List compartments
oci iam compartment list \
--compartment-id $TENANCY_ID \
--compartment-id-in-subtree true \
--all \
--output table
# List VCNs across all compartments
oci network vcn list \
--compartment-id $TENANCY_ID \
--all \
--output table
# List Security Zones
oci cloud-guard security-zone list \
--compartment-id $TENANCY_ID \
--compartment-id-in-subtree true \
--all \
--output table
# List Budgets
oci budgets budget list \
--compartment-id $TENANCY_ID \
--output tableGenerate Cost Report by Compartment
# Get usage data for compartment
oci usage-api usage summarized-usage get \
--tenant-id $TENANCY_ID \
--time-usage-started "2026-01-01T00:00:00Z" \
--time-usage-ended "2026-01-31T23:59:59Z" \
--granularity MONTHLY \
--query-type COST \
--group-by "[\"compartmentPath\"]" \
--output json | jq '.data.items[] | {
compartment: .tags["Oracle-Tags"]["CreatedBy"],
cost: .["computed-amount"]
}'Best Practices
Always Use --wait-for-state
# ✅ GOOD - waits for compartment to be active
oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Prod" \
--wait-for-state ACTIVE
# ❌ BAD - returns immediately, compartment may not be ready
oci iam compartment create \
--compartment-id $TENANCY_ID \
--name "Prod"Use Environment Variables for OCIDs
# ✅ GOOD - reusable, maintainable
PROD_CMP=$(oci iam compartment create ... --query 'data.id' --raw-output)
oci network vcn create --compartment-id $PROD_CMP
# ❌ BAD - error-prone
oci network vcn create --compartment-id ocid1.compartment.oc1..xxxDocument CIDR Allocations
# Maintain CIDR allocation table
cat > cidr-allocation.txt <<EOF
Hub VCN: 10.0.0.0/16
Spoke-App1-Prod: 10.10.0.0/16
Spoke-App1-Test: 10.20.0.0/16
Spoke-App1-Dev: 10.30.0.0/16
Spoke-App2-Prod: 10.40.0.0/16
On-premises: 172.16.0.0/12
Reserved-Future: 10.50.0.0/16 - 10.99.0.0/16
EOF
# Check for overlaps before creating VCN
grep "10.10.0.0" cidr-allocation.txtWhen to Use Landing Zone CLI
Use these commands when you need to:
- Set up initial OCI tenancy structure
- Create compartment hierarchies
- Implement Security Zones and Cloud Guard
- Configure tagging strategy
- Deploy hub-spoke network topology
- Create budgets and cost controls
- Implement multi-region DR
Don't use for:
- Individual resource creation (covered in service-specific skills)
- Day-to-day operations (use service-specific CLIs)
- Troubleshooting (covered in other skills)
OCI Landing Zone Patterns Reference
Landing Zone Topology Patterns
Pattern 1: Hub-Spoke Topology (Recommended for Multi-Tenancy)
┌─────────────────────────┐
│ Hub VCN (10.0.0.0/16) │
│ │
│ - Network Firewall │
│ - NAT Gateway │
│ - Service Gateway │
│ - DRG (on-prem) │
└────────────┬────────────┘
│
DRG
┌────────────┼────────────┐
│ │ │
┌───────────▼──┐ ┌──────▼─────┐ ┌──▼───────────┐
│ Spoke 1 VCN │ │ Spoke 2 VCN│ │ Spoke 3 VCN │
│ App1-Prod │ │ App2-Prod │ │ Shared-Svcs │
│ 10.10.0.0/16 │ │ 10.20.0.0/16│ │ 10.30.0.0/16 │
└──────────────┘ └────────────┘ └──────────────┘
Benefits:
- Centralized egress control (cost + security)
- Spoke isolation (network segmentation)
- Shared services (DNS, monitoring, bastion)
- Transitive routing via DRG
Cost savings: $3,000-5,000/month via single NAT Gateway vs per-VCNPattern 2: Multi-Compartment Hierarchy
Tenancy (Root)
│
├─ Network [Network admins only]
│ ├─ Hub
│ └─ Spokes
│
├─ Security [Security team only]
│ ├─ Vault (keys, secrets)
│ ├─ Bastion
│ └─ Logging (audit logs, flow logs)
│
├─ Workloads [Application teams]
│ ├─ App1
│ │ ├─ Dev [Developers full access]
│ │ ├─ Test [QA full access]
│ │ └─ Prod [SRE read, operators limited write]
│ │
│ └─ App2
│ ├─ Dev
│ ├─ Test
│ └─ Prod
│
├─ Shared-Services [Platform team]
│ ├─ Identity (IDCS, federation)
│ ├─ Monitoring (APM, Logging Analytics)
│ └─ DevOps (CI/CD, artifact registry)
│
└─ Sandbox [Developers experiment, auto-delete after 30 days]
├─ User1-Sandbox
└─ User2-Sandbox
Policy inheritance:
- Network policies apply to Hub + Spokes
- Workload policies apply to all App environments
- Sandbox policies enforce auto-cleanupPattern 3: Security Zones & Cloud Guard Integration
Compartment: Prod
│
├─ Security Zone Recipe: CIS-Level-1
│ ├─ deny-public-ip-on-compute
│ ├─ deny-public-bucket
│ ├─ require-encryption-at-rest
│ ├─ require-encryption-in-transit
│ └─ deny-internet-gateway-in-private-subnet
│
├─ Cloud Guard Target
│ ├─ Detector: Configuration issues
│ ├─ Detector: Activity anomalies
│ └─ Responder: Auto-remediate violations
│
└─ Resources
├─ Compute: Public IP blocked ✓
├─ Object Storage: Private only ✓
├─ ADB: TDE enabled ✓
└─ Load Balancer: SSL enforced ✓
Result: Security violations prevented at creation time, not detected afterCompartment Design Decision Tree
"How should I structure compartments?"
│
├─ Single application, simple lifecycle?
│ └─ Pattern: Workload-centric
│ Workloads/
│ └─ MyApp/
│ ├─ Dev
│ ├─ Test
│ └─ Prod
│
├─ Multiple applications, shared platform?
│ └─ Pattern: Environment-centric
│ Workloads/
│ ├─ Dev/
│ │ ├─ App1
│ │ └─ App2
│ ├─ Test/
│ │ ├─ App1
│ │ └─ App2
│ └─ Prod/
│ ├─ App1
│ └─ App2
│
├─ Multi-tenant SaaS (customers isolated)?
│ └─ Pattern: Tenant-centric
│ Tenants/
│ ├─ Customer-A/
│ │ ├─ Network
│ │ ├─ Compute
│ │ └─ Database
│ └─ Customer-B/
│ ├─ Network
│ ├─ Compute
│ └─ Database
│
└─ Large enterprise, multiple business units?
└─ Pattern: Business-unit-centric
BusinessUnits/
├─ BU-Engineering/
│ └─ [Workload-centric per BU]
├─ BU-Marketing/
│ └─ [Workload-centric per BU]
└─ BU-Sales/
└─ [Workload-centric per BU]
Key principle: Choose hierarchy that matches org structure + cost allocationNetwork Topology Decision Tree
"Which network pattern should I use?"
│
├─ Single application, no shared services?
│ └─ Single VCN
│ Cost: Lowest
│ Complexity: Simplest
│ Use when: Proof of concept, single app
│
├─ Multiple apps, need isolation, shared egress?
│ └─ Hub-Spoke via DRG
│ Cost: $100/month DRG + $45/month NAT (shared)
│ Complexity: Medium
│ Egress savings: $3,000-5,000/month
│ Use when: Multi-app production
│
├─ Multi-region disaster recovery?
│ └─ Hub-Spoke + DRG Remote Peering
│ Primary Region: Hub-Spoke
│ DR Region: Hub-Spoke
│ Cost: +$100/month DRG per region
│ Use when: RTO < 1 hour required
│
└─ On-premises integration?
└─ Hub-Spoke + FastConnect
Hub VCN: FastConnect → On-prem
Spokes: Route via hub
Cost: $500-2,000/month FastConnect
Use when: Hybrid cloud architectureTagging Strategy
Required Tags (Mandatory)
Tag Namespace: Organization
Tags:
- CostCenter: [Finance code for chargeback]
Type: String
Mandatory: Yes
Default: None
- Environment: [Dev | Test | Prod | Sandbox]
Type: Enum
Mandatory: Yes
Default: None
- Owner: [Email or team name]
Type: String
Mandatory: Yes
Default: ${iam.principal.name}
- DataClassification: [Public | Internal | Confidential | Restricted]
Type: Enum
Mandatory: Yes (for data resources)
Default: Internal
- BackupPolicy: [None | Bronze | Silver | Gold]
Type: Enum
Mandatory: Yes (for stateful resources)
Default: BronzeOptional Tags (Recommended)
- Project: [Project or product name]
- ExpiryDate: [Auto-cleanup date for sandbox]
- Compliance: [PCI | HIPAA | SOC2]
- ManagedBy: [Terraform | Manual | Ansible]Cost Allocation Patterns
Budget Hierarchy
Tenancy Budget: $100,000/month
├─ Network: $10,000/month (fixed)
├─ Security: $5,000/month (fixed)
├─ Workloads: $75,000/month
│ ├─ App1-Dev: $5,000/month
│ ├─ App1-Test: $8,000/month
│ ├─ App1-Prod: $25,000/month
│ ├─ App2-Dev: $3,000/month
│ ├─ App2-Test: $4,000/month
│ └─ App2-Prod: $30,000/month
└─ Shared-Services: $10,000/month
Alerts:
- 50% threshold: Warning
- 80% threshold: Critical (page on-call)
- 100% threshold: Auto-stop dev/test resourcesOCI Landing Zone and Well-Architected Reference
Use this as a source map for landing zone, compartment, and governance work.
Official Oracle Sources
- OCI Architecture Center: https://docs.oracle.com/en/solutions/
- Cloud Adoption Framework landing zone: https://docs.oracle.com/en-us/iaas/Content/cloud-adoption-framework/landing-zone.htm
- Security Zones: https://docs.oracle.com/en-us/iaas/Content/Security/Concepts/securityzones.htm
- Cloud Guard: https://docs.oracle.com/en-us/iaas/Content/cloud-adoption-framework/security-guardrails.htm
- CIS OCI Foundations Benchmark: https://www.cisecurity.org/benchmark/oracle_cloud
Load Guidance
Use Oracle docs for current landing-zone concepts and CIS for benchmark controls. Avoid relying on old blog scrape content for current module names or support status.
Security Zone Automation Runbook
Use this playbook when rolling out Security Zones, recipes, and monitoring at scale across compartments/environments. All commands assume OCI CLI.
1. Define Security Policies (Recipe)
RECIPE_NAME="CIS-Prod-Recipe"
OCI_REGION="us-ashburn-1"
oci cloud-guard security-policy list --all \
--query 'data[].{"name":"display-name","id":"id"}' --output table
# capture policy OCIDs you want to enforce
# Example filters for specific display names
POLICY_IDS_JSON=$(oci cloud-guard security-policy list --all \
--query 'data[?"display-name"==`deny-public-ip` || "display-name"==`deny-public-bucket` || "display-name"==`require-encryption`].id')
oci cloud-guard security-zone-recipe create \
--compartment-id "$TENANCY_OCID" \
--display-name "$RECIPE_NAME" \
--security-policies "$POLICY_IDS_JSON"
RECIPE_ID=$(oci cloud-guard security-zone-recipe list --compartment-id "$TENANCY_OCID" \
--display-name "$RECIPE_NAME" --query 'data[0].id' --raw-output)2. Apply Recipe to Compartments
for COMPARTMENT in $(jq -r '.compartments[].id' compartments.json); do
oci cloud-guard security-zone create \
--compartment-id "$COMPARTMENT" \
--display-name "$(oci iam compartment get --compartment-id "$COMPARTMENT" --query 'data."name"' --raw-output)-SZ" \
--security-zone-recipe-id "$RECIPE_ID" \
--wait-for-state ACTIVE
doneTip: Generate compartments.json via oci iam compartment list --all --compartment-id $TENANCY_OCID and filter by tag (e.g., Environment=Prod).
3. Automate with Terraform
resource "oci_cloud_guard_security_zone" "prod" {
compartment_id = oci_identity_compartment.prod.id
display_name = "${var.compartment_name}-security-zone"
security_zone_recipe_id = oci_cloud_guard_security_zone_recipe.prod.id
}
data "oci_cloud_guard_security_policies" "all" {
compartment_id = var.tenancy_ocid
}
locals {
required_policy_names = ["deny-public-ip", "deny-public-bucket", "require-cmk-encryption"]
}
resource "oci_cloud_guard_security_zone_recipe" "prod" {
compartment_id = var.tenancy_ocid
display_name = "CIS-Prod"
security_policies = [
for policy in data.oci_cloud_guard_security_policies.all.security_policies : policy.id
if contains(local.required_policy_names, policy.display_name)
]
}Apply after any manual change so state remains accurate.
4. Verification Commands
oci cloud-guard security-zone get --security-zone-id $ZONE_ID --query 'data."lifecycle-state"'
oci cloud-guard security-zone list --compartment-id $TENANCY_OCID --all --output table
oci cloud-guard security-zone list-problems --security-zone-id $ZONE_ID --all --output tableAlert SRE if any compartment re-enters PROBLEM state after remediation.
5. Rollback / Removal
oci cloud-guard security-zone delete --security-zone-id $ZONE_ID --force
oci cloud-guard security-zone-recipe delete --security-zone-recipe-id $RECIPE_ID --forceOnly remove zones with compliance approval. Document reason in incident ticket.
OCI Managed Bastion Reference
Use this focused reference for OCI Bastion operations and troubleshooting. Verify live limits, service availability, and IAM details against Oracle docs before production changes.
Official Sources
- Bastion overview: https://docs.oracle.com/iaas/Content/Bastion/Concepts/bastionoverview.htm
- Creating a Managed SSH session: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/create-session-managed-ssh.htm
- Connecting to Managed SSH: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/connect-managed-ssh.htm
- Connecting to port forwarding: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/connect-port-forwarding.htm
- Bastion IAM policies: https://docs.oracle.com/en-us/iaas/Content/Bastion/Reference/bastionpolicyreference.htm
- Bastion known issues: https://docs.oracle.com/en-us/iaas/Content/Bastion/Tasks/known-issues.htm
Session Types
| Session type | Use for | Key requirements |
|---|---|---|
| Managed SSH | SSH to supported Linux Compute | OpenSSH, Oracle Cloud Agent, Bastion plugin enabled |
| Port forwarding | One TCP target/port | Client in allowlist, target allows traffic from bastion |
| Dynamic port forwarding | SOCKS5 access to multiple subnet targets | Client SOCKS5 support, target-side network rules |
Oracle docs state that a bastion is associated with a single VCN. Do not design a bastion in one VCN as a direct access path to targets in another VCN unless an officially supported network pattern is confirmed for the exact target.
Access Checklist
1. Caller has IAM permissions for bastion and session operations. 2. Bastion client CIDR allowlist includes the caller's current public IP or approved range. 3. Target resource is private and reachable from the bastion's VCN path. 4. Target-side NSGs/security lists allow the bastion path and target port. 5. Session is ACTIVE and not expired. 6. SSH private key matches the public key used at session creation. 7. OS username matches the target image, often opc for Oracle platform images. 8. For Managed SSH, Oracle Cloud Agent and Bastion plugin are installed, enabled, and running.
Operational Lessons
- The Console/API minimum session TTL is 30 minutes and maximum is 180 minutes.
- ACTIVE session state is necessary but not sufficient; SSH can still close immediately if plugin, key, username, target port, or network rules are wrong.
- For CLI-created sessions, inspect the returned session OCID and poll the session directly instead of relying only on work-request output shape.
- For temporary client-IP access, read the bastion immediately before update and use ETag-safe mutation. If the update fails with an ETag mismatch, re-read and retry with the new ETag.
- After temporary access, delete sessions and remove temporary CIDRs from the allowlist. Verify the final state.
Known Managed SSH Pitfalls
| Symptom | Likely checks |
|---|---|
| Session creation fails on Ampere A1 Ubuntu | Oracle docs identify Managed SSH support issues; use port forwarding or update/enable Oracle Cloud Agent and plugin |
| Session ACTIVE but SSH closes immediately | Plugin health, OS username, key mismatch, target IP/port, target-side NSG/security list |
| Client cannot connect to session host | Client CIDR allowlist, local firewall/proxy, copied SSH command, private key permissions |
| Port forwarding opens but target protocol fails | Local port mapping, target listener, NSG/security list, database/listener ACL |
| Dynamic SOCKS tunnel connects but app fails | App proxy settings, DNS behavior, target-side rules, route path |
Allowlist Mutation Guardrail
When temporarily adding a client IP:
1. Resolve the user's current public IP from an approved source. 2. Convert to a single-host CIDR when appropriate. 3. Read current bastion details and ETag. 4. Add the CIDR without removing unrelated CIDRs. 5. Update with the current ETag. 6. Verify final allowlist. 7. Record cleanup time and remove the temporary CIDR after use.
Pressure Scenarios
- "Managed SSH session is ACTIVE but SSH closes immediately."
- "Bastion session creation fails on Ubuntu/Ampere."
- "Temporarily add my current IP to the Bastion allowlist."
- "Terraform should create a Bastion for private instance access."
{
"schemaVersion": 1,
"packSkill": "oci",
"purpose": "Canonical ownership boundary for OCI and Oracle-related skills in agentic-tools.",
"groups": [
{
"name": "core-oci-operations",
"description": "OCI service operation, architecture, governance, automation, observability, cost, AI, events, secrets, and database skills.",
"skills": [
"oci/best-practices",
"oci/compute-management",
"oci/database-management",
"oci/finops-cost-optimization",
"oci/genai-services",
"oci/iam-identity-management",
"oci/infrastructure-as-code",
"oci/landing-zones",
"oci/monitoring-operations",
"oci/networking-management",
"oci/oci-events",
"oci/managed-bastion-access",
"oci/oci-resource-manager",
"oci/oci-security-control-plane",
"oci/zpr-security",
"oci/oracle-dba",
"oci/secrets-management"
]
},
{
"name": "oracle-adjacent",
"description": "Oracle identity, migration, app integration, and branded artifact skills that should remain distinct from core OCI operations.",
"skills": [
"oci/fastify-better-auth-bridge",
"oci/oci-pptx",
"oci/oracle-idcs-better-auth-setup",
"oci/oracle-idcs-org-provisioning",
"oci/sqlite-to-oracle-planner"
]
},
{
"name": "pack-and-routing",
"description": "Compatibility and routing entry points for OCI skill discovery and ownership.",
"skills": [
"oci",
"oci/best-practices",
"oci/database-management",
"oci/oci-security-control-plane"
]
}
],
"reviewTriggers": [
"Oracle documentation drift",
"OCI pricing, limits, quotas, model catalogs, or service availability changes",
"Identity Domains or IDCS terminology changes",
"New OCI specialist skill added to skills/",
"Installer, marketplace, or external skill publishing changes"
]
}
OCI Monitoring and Operations Reference
Use this as a source map for metrics, alarms, logs, and service connector work.
Official Oracle Sources
- Monitoring overview: https://docs.oracle.com/en-us/iaas/Content/Monitoring/Concepts/monitoringoverview.htm
- MQL reference: https://docs.oracle.com/en-us/iaas/Content/Monitoring/Reference/mql.htm
- Alarms: https://docs.oracle.com/en-us/iaas/Content/Monitoring/Tasks/managingalarms.htm
- Logging overview: https://docs.oracle.com/en-us/iaas/Content/Logging/Concepts/loggingoverview.htm
- Service Connector Hub: https://docs.oracle.com/en-us/iaas/Content/service-connector-hub/overview.htm
Load Guidance
Open the relevant service metric reference before quoting metric names or dimensions.
OCI Networking Reference
Use this as a source map. Open current Oracle docs before quoting limits or service behavior.
Official Oracle Sources
- VCNs and subnets: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/VCNs.htm
- Add a VCN CIDR block: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/add_cidr_to_vcn.htm
- Modify a VCN CIDR block: https://docs.oracle.com/en-us/iaas/tools/oci-cli/latest/oci_cli_docs/cmdref/network/vcn/modify-vcn-cidr.html
- Service Gateway: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/servicegateway.htm
- Dynamic Routing Gateways: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/managingDRGs.htm
- FastConnect: https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/fastconnect.htm
Load Guidance
Search this file for the service name, then open the corresponding Oracle page. Do not treat cached limits or prices as current.
OCI Terraform Networking Patterns
Use this reference when Terraform manages OCI VCNs, subnets, route tables, gateways, DRGs, private endpoints, DNS, NSGs, or security lists.
Official Sources
- OCI Networking overview: https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/overview.htm
- VCN management: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/managingVCNs.htm
- Security rules: https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/securityrules.htm
- Service Gateway: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/servicegateway.htm
- Dynamic Routing Gateways: https://docs.oracle.com/en-us/iaas/Content/Network/Tasks/managingDRGs.htm
- OCI Terraform provider networking resources: https://registry.terraform.io/providers/oracle/oci/latest/docs
- Resource Manager private endpoints: https://docs.oracle.com/iaas/Content/ResourceManager/Tasks/private-endpoints.htm
Terraform Design Rules
- Use
for_eachwith stable keys for subnets, route rules, NSGs, and security rules. Avoidcountwhen list reorder could replace resources. - Attach explicit route tables, DHCP options, security lists, and NSGs. Do not rely on defaults except intentionally.
- Use NSGs for application-tier policy and security lists for subnet baseline rules.
- Keep route table ownership clear. A subnet can have one route table association, so module boundaries must not compete for it.
- Treat VCN CIDR add/modify as supported but controlled. Check overlap with subnets, peers, DRG routes, DNS, and security rules before changing.
- Import existing VCN, subnet, gateway, DRG, and route resources before applying modules to brownfield networks.
Common Traps
| Trap | Safer behavior |
|---|---|
| NSG vs security list confusion | NSG for workload-specific rules; security list for subnet baseline |
| Default route table drift | Create custom route tables and associate subnets explicitly |
| Service Gateway missing route | Add OSN/service CIDR route to the private subnet route table |
| NAT Gateway overuse | Use live pricing and consider Service Gateway/private endpoints first |
| DRG v2 route distribution ignored | Model attachments, route tables, route distributions, and imports explicitly |
| Private endpoint unreachable | Verify DNS, route table, subnet, NSG/security list, and endpoint-specific docs |
| VCN CIDR treated as immutable | OCI supports add/modify with restrictions; plan the blast radius |
Resource Manager Private Endpoint Note
Resource Manager private endpoints are Resource Manager resources, not generic VCN endpoints. Use them when Resource Manager jobs must reach private Git, private compute, or private services. Route Resource Manager-specific troubleshooting to oci/oci-resource-manager.
Cost and Limit Rules
- Do not quote static NAT Gateway, FastConnect, VPN, public IP, or egress prices from memory.
- Check live Oracle pricing for the target region and subscription model.
- Check service limits and quotas before assuming a Terraform plan can be applied.
- Distinguish "out of host capacity" from service-limit exhaustion and regional availability.
Pressure Scenarios
- "Terraform created the subnet but traffic fails": inspect route table association, security list/NSG, gateway route, DNS, and stateful rule assumptions.
- "Can Terraform resize this VCN?": do not say impossible; check OCI CIDR add/modify restrictions and overlap blast radius.
- "Resource Manager cannot remote-exec into a private instance": route to Resource Manager private endpoint checks plus subnet security rules.
OCI CLI for Events Service Operations
Complete OCI CLI commands for event-driven automation and event rule management.
Prerequisites
# Verify OCI CLI and authentication
oci --version
oci iam region list --output table
# Get compartment ID
export COMPARTMENT_ID=$(oci iam compartment list \
--name "YourCompartment" \
--query 'data[0].id' \
--raw-output)
echo "Compartment: $COMPARTMENT_ID"List Available Event Types
# List all event types across OCI services
oci events event-type list --all --output table
# Filter by service (e.g., compute)
oci events event-type list \
--all \
| jq '.data[] | select(.name | contains("compute"))'
# Common event types by service
oci events event-type list --all \
| jq -r '.data[] | .name' \
| grep -E "^com.oraclecloud.(compute|database|objectstorage|iam)"
# Get specific event type details
oci events event-type get \
--event-type "com.oraclecloud.computeapi.launchinstance"Create Event Rules
Basic Event Rule (Single Event Type)
# Rule: Notify when compute instance is terminated
oci events rule create \
--display-name "Compute-Instance-Terminated" \
--description "Alert when any compute instance is terminated" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.computeapi.terminateinstance"
}' \
--actions '{
"actions": [{
"actionType": "ONS",
"isEnabled": true,
"topicId": "ocid1.onstopic.oc1..xxx",
"description": "Send notification to SRE team"
}]
}'Event Rule with Compartment Filter
# Rule: Alert only for production compartment events
oci events rule create \
--display-name "Prod-Database-Stopped" \
--description "Alert when production database is stopped" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.databaseservice.stopautonomousdatabase",
"data": {
"compartmentName": "Prod"
}
}' \
--actions '{
"actions": [{
"actionType": "ONS",
"isEnabled": true,
"topicId": "ocid1.onstopic.oc1..xxx",
"description": "CRITICAL: Prod database stopped"
}]
}'Event Rule with Resource Name Pattern
# Rule: Process CSV files uploaded to Object Storage
oci events rule create \
--display-name "Process-CSV-Uploads" \
--description "Trigger function for CSV file uploads" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.objectstorage.createobject",
"data": {
"resourceName": "*.csv"
}
}' \
--actions '{
"actions": [{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "ocid1.fnfunc.oc1..xxx",
"description": "Parse and load CSV data"
}]
}'Event Rule with Multiple Event Types
# Rule: Monitor compute instance lifecycle (create + delete)
oci events rule create \
--display-name "Compute-Lifecycle-Audit" \
--description "Log all compute instance creates and deletes" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": [
"com.oraclecloud.computeapi.launchinstance",
"com.oraclecloud.computeapi.terminateinstance"
]
}' \
--actions '{
"actions": [{
"actionType": "OSS",
"isEnabled": true,
"streamId": "ocid1.stream.oc1..xxx",
"description": "Stream to audit log"
}]
}'Event Rule with Tag Filters
# Rule: Alert for changes to tagged resources
oci events rule create \
--display-name "Critical-Resource-Changes" \
--description "Alert for changes to critical infrastructure" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.computeapi.*",
"data": {
"freeformTags": {
"Criticality": "High"
}
}
}' \
--actions '{
"actions": [{
"actionType": "ONS",
"isEnabled": true,
"topicId": "ocid1.onstopic.oc1..xxx",
"description": "Critical resource event"
}]
}'Event Rule with Multiple Actions (Fan-Out)
# Rule: Multiple actions for same event
oci events rule create \
--display-name "IAM-Policy-Changed-Multi-Action" \
--description "Multiple responses to IAM policy changes" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.identityControlPlane.UpdatePolicy"
}' \
--actions '{
"actions": [
{
"actionType": "ONS",
"isEnabled": true,
"topicId": "ocid1.onstopic.oc1..xxx",
"description": "Email security team"
},
{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "ocid1.fnfunc.oc1..xxx",
"description": "Log to SIEM"
},
{
"actionType": "OSS",
"isEnabled": true,
"streamId": "ocid1.stream.oc1..xxx",
"description": "Stream for audit compliance"
}
]
}'
# LIMIT: Maximum 5 actions per ruleManage Event Rules
List Event Rules
# List all event rules in compartment
oci events rule list \
--compartment-id $COMPARTMENT_ID \
--lifecycle-state ACTIVE \
--output table
# Get specific rule details
RULE_ID="ocid1.eventsrule.oc1..xxx"
oci events rule get --rule-id $RULE_ID
# List rules with specific display name
oci events rule list \
--compartment-id $COMPARTMENT_ID \
--display-name "Compute-Instance-Terminated" \
--output jsonUpdate Event Rule
# Enable/disable rule
oci events rule update \
--rule-id $RULE_ID \
--is-enabled false
# Update rule condition
oci events rule update \
--rule-id $RULE_ID \
--condition '{
"eventType": [
"com.oraclecloud.computeapi.launchinstance",
"com.oraclecloud.computeapi.terminateinstance",
"com.oraclecloud.computeapi.changeinstanceshape"
]
}'
# Add new action to existing rule
oci events rule update \
--rule-id $RULE_ID \
--actions '{
"actions": [
{
"actionType": "ONS",
"isEnabled": true,
"topicId": "ocid1.onstopic.oc1..xxx"
},
{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "ocid1.fnfunc.oc1..xxx"
}
]
}'Delete Event Rule
# Delete specific rule
oci events rule delete \
--rule-id $RULE_ID \
--force
# Verify deletion
oci events rule list \
--compartment-id $COMPARTMENT_ID \
--lifecycle-state DELETED \
--output tableIAM Policies for Events
Grant Events Permission to Invoke Functions
# Policy: Allow Events service to invoke all functions in compartment
oci iam policy create \
--compartment-id $COMPARTMENT_ID \
--name "Events-Invoke-Functions-Policy" \
--description "Allow Events service to trigger Functions" \
--statements '[
"Allow service cloudEvents to use functions-family in compartment <compartment-name>"
]'
# Policy: Allow Events to invoke specific function
oci iam policy create \
--compartment-id $COMPARTMENT_ID \
--name "Events-Invoke-Specific-Function-Policy" \
--description "Allow Events to invoke CSV processor function" \
--statements '[
"Allow service cloudEvents to use fn-function in compartment <compartment-name> where target.function.id = \"ocid1.fnfunc.oc1..xxx\""
]'Grant Events Permission to Publish to ONS
# Policy: Allow Events to publish to Notification topics
oci iam policy create \
--compartment-id $COMPARTMENT_ID \
--name "Events-Publish-ONS-Policy" \
--description "Allow Events to send notifications" \
--statements '[
"Allow service cloudEvents to use ons-topics in compartment <compartment-name>"
]'Grant Events Permission to Write to Streaming
# Policy: Allow Events to publish to Streaming
oci iam policy create \
--compartment-id $COMPARTMENT_ID \
--name "Events-Publish-Streaming-Policy" \
--description "Allow Events to write to Streaming" \
--statements '[
"Allow service cloudEvents to use stream-push in compartment <compartment-name>"
]'Testing and Debugging
Test Event Rule Condition
# Get sample event payload for event type
oci events event-type get \
--event-type "com.oraclecloud.computeapi.launchinstance" \
| jq '.data."schema"'
# Manually trigger event (for testing)
# Note: OCI Events doesn't support manual event injection
# Test by performing the actual action (e.g., launch instance)
# Check rule execution history (via monitoring)
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'RulesEvaluated[1m].count()' \
--start-time "2026-01-28T00:00:00Z" \
--end-time "2026-01-28T23:59:59Z"Check Event Rule Metrics
# Get rule evaluation count
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'RulesEvaluated[5m]{ruleId="'$RULE_ID'"}.count()' \
--start-time "2026-01-28T10:00:00Z" \
--end-time "2026-01-28T11:00:00Z"
# Get action execution count
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'ActionsExecuted[5m]{ruleId="'$RULE_ID'"}.count()' \
--start-time "2026-01-28T10:00:00Z" \
--end-time "2026-01-28T11:00:00Z"
# Get failed action count
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'ActionsFailed[5m]{ruleId="'$RULE_ID'"}.count()' \
--start-time "2026-01-28T10:00:00Z" \
--end-time "2026-01-28T11:00:00Z"Common Event Patterns
Pattern 1: Object Storage Upload → Function Processing
# Create notification topic
ONS_TOPIC=$(oci ons topic create \
--compartment-id $COMPARTMENT_ID \
--name "CSV-Processing-Topic" \
--wait-for-state ACTIVE \
--query 'data.id' --raw-output)
# Create function (assume already deployed)
FUNCTION_ID="ocid1.fnfunc.oc1..xxx"
# Create event rule
oci events rule create \
--display-name "Object-Upload-Processing" \
--description "Process files uploaded to Object Storage" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.objectstorage.createobject",
"data": {
"additionalDetails": {
"bucketName": "data-ingestion"
}
}
}' \
--actions '{
"actions": [{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "'$FUNCTION_ID'",
"description": "Process uploaded file"
}]
}'Pattern 2: IAM Changes → Security Audit
# Create streaming for audit trail
STREAM_ID=$(oci streaming admin stream create \
--compartment-id $COMPARTMENT_ID \
--name "IAM-Audit-Stream" \
--partitions 1 \
--wait-for-state ACTIVE \
--query 'data.id' --raw-output)
# Create event rule for IAM changes
oci events rule create \
--display-name "IAM-Changes-Audit" \
--description "Audit all IAM policy and user changes" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": [
"com.oraclecloud.identityControlPlane.CreateUser",
"com.oraclecloud.identityControlPlane.UpdateUser",
"com.oraclecloud.identityControlPlane.DeleteUser",
"com.oraclecloud.identityControlPlane.CreatePolicy",
"com.oraclecloud.identityControlPlane.UpdatePolicy",
"com.oraclecloud.identityControlPlane.DeletePolicy"
]
}' \
--actions '{
"actions": [
{
"actionType": "ONS",
"isEnabled": true,
"topicId": "'$ONS_TOPIC'",
"description": "Alert security team"
},
{
"actionType": "OSS",
"isEnabled": true,
"streamId": "'$STREAM_ID'",
"description": "Stream to SIEM"
}
]
}'Pattern 3: Database Lifecycle → Compliance Check
# Create event rule for database operations
oci events rule create \
--display-name "Database-Lifecycle-Compliance" \
--description "Compliance checks for database operations" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": [
"com.oraclecloud.databaseservice.createautonomousdatabase",
"com.oraclecloud.databaseservice.deleteautonomousdatabase",
"com.oraclecloud.databaseservice.updateautonomousdatabase"
],
"data": {
"compartmentName": "Prod"
}
}' \
--actions '{
"actions": [{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "'$FUNCTION_ID'",
"description": "Check encryption, backup policy, tags"
}]
}'Pattern 4: Compute Instance State → Cost Optimization
# Create event rule to detect long-running dev instances
oci events rule create \
--display-name "Dev-Instance-Running-Alert" \
--description "Alert when dev instances run beyond business hours" \
--is-enabled true \
--compartment-id $COMPARTMENT_ID \
--condition '{
"eventType": "com.oraclecloud.computeapi.launchinstance",
"data": {
"freeformTags": {
"Environment": "Dev"
}
}
}' \
--actions '{
"actions": [{
"actionType": "FAAS",
"isEnabled": true,
"functionId": "'$FUNCTION_ID'",
"description": "Schedule auto-shutdown at 6pm"
}]
}'Troubleshooting
Event Rule Not Firing
# 1. Check if rule is enabled
oci events rule get --rule-id $RULE_ID \
| jq '.data."is-enabled"'
# 2. Check if event type is correct
oci events event-type list --all \
| jq -r '.data[] | .name' \
| grep -i "compute"
# 3. Check IAM policies
oci iam policy list \
--compartment-id $COMPARTMENT_ID \
| jq '.data[] | select(.name | contains("Events"))'
# 4. Check rule metrics (did rule evaluate?)
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'RulesEvaluated[5m]{ruleId="'$RULE_ID'"}.count()' \
--start-time "2026-01-28T10:00:00Z" \
--end-time "2026-01-28T11:00:00Z"Action Failing (Function Not Invoked)
# 1. Check action failures metric
oci monitoring metric-data summarize-metrics-data \
--namespace oci_events \
--compartment-id $COMPARTMENT_ID \
--query-text 'ActionsFailed[5m]{ruleId="'$RULE_ID'"}.count()' \
--start-time "2026-01-28T10:00:00Z" \
--end-time "2026-01-28T11:00:00Z"
# 2. Check IAM policy for Functions
oci iam policy list \
--compartment-id $COMPARTMENT_ID \
| jq '.data[] | select(.statements[] | contains("cloudEvents"))'
# 3. Check function logs
oci logging log list \
--log-group-id "ocid1.loggroup.oc1..xxx" \
--output table
# 4. Verify function exists and is active
oci fn function get --function-id $FUNCTION_IDEvent Filter Not Matching
# Get event type schema to understand available fields
oci events event-type get \
--event-type "com.oraclecloud.objectstorage.createobject" \
| jq '.data.schema'
# Common filter fields:
# - compartmentName: Name of compartment
# - compartmentId: OCID of compartment
# - resourceName: Resource name (supports wildcards *)
# - freeformTags: User-defined tags
# - definedTags: Defined tag namespaces
# Test filter specificity
# Too broad: All compute events
{"eventType": "com.oraclecloud.computeapi.*"}
# More specific: Only instance launches in prod
{
"eventType": "com.oraclecloud.computeapi.launchinstance",
"data": {"compartmentName": "Prod"}
}Best Practices
Use Specific Event Types (Not Wildcards)
# ❌ BAD - matches all 50+ compute event types
oci events rule create \
--condition '{"eventType": "com.oraclecloud.computeapi.*"}' \
...
# ✅ GOOD - matches only critical lifecycle events
oci events rule create \
--condition '{
"eventType": [
"com.oraclecloud.computeapi.launchinstance",
"com.oraclecloud.computeapi.terminateinstance"
]
}' \
...Always Set IAM Policies First
# 1. Create IAM policy
oci iam policy create \
--compartment-id $COMPARTMENT_ID \
--name "Events-Functions-Policy" \
--statements '["Allow service cloudEvents to use functions-family in compartment MyCompartment"]'
# 2. Wait for policy to propagate (30 seconds)
sleep 30
# 3. Create event rule
oci events rule create \
--condition '...' \
--actions '...'Monitor Event Rule Health
# Create alarm for failed actions
oci monitoring alarm create \
--compartment-id $COMPARTMENT_ID \
--display-name "Events-Actions-Failed-Alarm" \
--namespace "oci_events" \
--query-text 'ActionsFailed[1m].sum() > 0' \
--severity "CRITICAL" \
--destinations '["'$ONS_TOPIC'"]' \
--is-enabled trueUse Descriptive Names
# ✅ GOOD - clear purpose
--display-name "Prod-Database-Stopped-Alert"
--description "Critical: Production database stopped - requires immediate investigation"
# ❌ BAD - unclear
--display-name "Rule-1"
--description "Database rule"When to Use OCI Events CLI
Use these commands when you need to:
- Create event-driven automation workflows
- Set up event rules with custom filters
- Troubleshoot event delivery issues
- Test event patterns and actions
- Quick prototypes before Terraform implementation
Don't use for:
- Production deployments (use OCI Landing Zone Terraform modules)
- Complex multi-rule architectures (use Terraform)
- When IaC governance is required (use Terraform)
OCI Events Service - Patterns Reference
Event-Driven Architecture Patterns
Pattern 1: Object Storage Upload → Function Processing
┌─────────────────┐
│ Object Storage │
│ - User uploads │
│ file.csv │
└────────┬────────┘
│ Event: createObject
▼
┌─────────────────┐
│ Events Rule │
│ Filter: .csv │
└────────┬────────┘
│ Invoke
▼
┌─────────────────┐
│ Function │
│ - Parse CSV │
│ - Store in DB │
│ - Send email │
└─────────────────┘
Event Filter:
{
"eventType": "com.oraclecloud.objectstorage.createobject",
"data": {
"additionalDetails": {
"eTag": "*"
},
"resourceName": "*.csv"
}
}
Use case: Data ingestion pipeline, document processingPattern 2: Compute Instance Lifecycle → Compliance Check
┌──────────────────┐
│ Compute Instance │
│ - Terminated │
│ - Created │
└────────┬─────────┘
│ Event: terminateInstance
▼
┌──────────────────┐
│ Events Rule │
│ Filter: Prod │
└────────┬─────────┘
│ Notify
▼
┌──────────────────┐ ┌──────────────────┐
│ Notification │────▶│ PagerDuty │
│ Topic │ │ (On-call) │
└──────────────────┘ └──────────────────┘
Event Filter:
{
"eventType": "com.oraclecloud.computeapi.terminateinstance",
"data": {
"compartmentName": "Prod"
}
}
Use case: Security monitoring, audit trail, incident responsePattern 3: Fan-Out (1 Event → Multiple Actions)
┌─────────────────┐
│ Database │
│ - Stopped │
└────────┬────────┘
│ Event: stopAutonomousDatabase
▼
┌─────────────────────────────────────┐
│ Events Rule │
│ Actions: │
│ 1. Notification → Email SRE │
│ 2. Function → Log to Splunk │
│ 3. Streaming → Analytics │
└─────────────────────────────────────┘
Use case: Multi-channel alerting, compliance logging, analytics
Max actions: 5 per rulePattern 4: Event Chaining (Event → Function → Event)
┌──────────────┐
│ IAM Policy │
│ - Changed │
└──────┬───────┘
│ Event 1
▼
┌──────────────┐
│ Function 1 │
│ - Audit log │
│ - Create │
│ ticket │
└──────┬───────┘
│ Custom Event
▼
┌──────────────┐
│ Function 2 │
│ - Compliance │
│ check │
└──────────────┘
Implementation: Functions can emit custom events using Events API
Use case: Complex workflows, approval chainsEvent Filter Syntax Decision Tree
"How should I filter events?"
│
├─ Filter by event type only (all occurrences)?
│ └─ Simple filter
│ {
│ "eventType": "com.oraclecloud.computeapi.launchinstance"
│ }
│
├─ Filter by compartment or tag?
│ └─ Compartment filter
│ {
│ "eventType": "com.oraclecloud.computeapi.launchinstance",
│ "data": {
│ "compartmentName": "Prod"
│ }
│ }
│
├─ Filter by resource attribute (name pattern)?
│ └─ Attribute filter
│ {
│ "eventType": "com.oraclecloud.objectstorage.createobject",
│ "data": {
│ "resourceName": "*.pdf"
│ }
│ }
│
├─ Filter by multiple event types?
│ └─ Array of event types
│ {
│ "eventType": [
│ "com.oraclecloud.computeapi.launchinstance",
│ "com.oraclecloud.computeapi.terminateinstance"
│ ]
│ }
│
└─ Complex logic (AND/OR conditions)?
└─ Use Cloud Events JSONPath
{
"eventType": "com.oraclecloud.computeapi.*",
"data": {
"freeformTags": {
"Environment": "Prod"
},
"definedTags": {
"Operations.CostCenter": "Engineering"
}
}
}Common Event Types by Service
Compute (com.oraclecloud.computeapi.*):
├─ launchinstance # Instance created
├─ terminateinstance # Instance deleted
├─ instanceaction # Reboot, stop, start
├─ changeinstanceshape # Shape changed (resize)
└─ attachvnic # Network interface attached
Database (com.oraclecloud.databaseservice.*):
├─ createautonomousdatabase # ADB created
├─ stopautonomousdatabase # ADB stopped
├─ startautonomousdatabase # ADB started
├─ deleteautonomousdatabase # ADB deleted
└─ updateautonomousdatabase # ADB scaled/modified
Object Storage (com.oraclecloud.objectstorage.*):
├─ createobject # File uploaded
├─ deleteobject # File deleted
├─ updateobject # File modified
└─ createbucket # Bucket created
IAM (com.oraclecloud.identityControlPlane.*):
├─ CreateUser # User added
├─ UpdateUser # User modified
├─ CreatePolicy # Policy created
├─ UpdatePolicy # Policy changed
└─ DeleteUser # User removed
VCN (com.oraclecloud.virtualnetwork.*):
├─ CreateVcn # VCN created
├─ DeleteVcn # VCN deleted
├─ CreateSubnet # Subnet created
├─ CreateSecurityList # Security list created
└─ CreateNetworkSecurityGroup # NSG created
Complete list: 100+ event types across all OCI services
Use: oci events event-type list --allAction Types and Use Cases
| Action Type | Target | Use Case | Cost | Max Actions |
|---|---|---|---|---|
| ONS | Notification Topic | Email, PagerDuty, webhook | $0.60/million | 5 |
| FAAS | Function | Data processing, API calls | $0.0000002/GB-sec | 5 |
| OSS | Streaming | High-volume event buffer | $0.025/stream-hour | 5 |
Choosing Action Type:
- 1-10 events/minute → ONS (notifications)
- 10-1000 events/minute → FAAS (processing)
- >1000 events/minute → OSS (streaming buffer)
OCI Events Reference
Use this as a source map for Events rules, filters, and actions.
Official Oracle Sources
- Events overview: https://docs.oracle.com/en-us/iaas/Content/Events/Concepts/eventsoverview.htm
- Creating event rules: https://docs.oracle.com/en-us/iaas/Content/Events/Tasks/create-events-rule.htm
- Event producers and event types: https://docs.oracle.com/en-us/iaas/Content/Events/Reference/eventsproducers.htm
- Oracle Functions: https://docs.oracle.com/en-us/iaas/Content/Functions/Concepts/functionsoverview.htm
- Streaming: https://docs.oracle.com/en-us/iaas/Content/Streaming/Concepts/streamingoverview.htm
- Notifications: https://docs.oracle.com/en-us/iaas/Content/Notification/Concepts/notificationoverview.htm
Load Guidance
Do not claim built-in failed-delivery DLQ semantics unless the current Events action documentation explicitly supports it. Use Streaming as durable capture/replay when the architecture requires replay.
Editing Presentations
Template-Based Workflow
When using an existing presentation as a template:
1. Analyze existing slides:
python scripts/thumbnail.py template.pptx
python -m markitdown template.pptxReview thumbnails.jpg to see layouts, and markitdown output to see placeholder text.
2. Plan slide mapping: For each content section, choose a template slide.
⚠️ USE VARIED LAYOUTS — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:
- Multi-column layouts (2-column, 3-column)
- Image + text combinations
- Full-bleed images with text overlay
- Quote or callout slides
- Section dividers
- Stat/number callouts
- Icon grids or icon + text rows
Avoid: Repeating the same text-heavy layout for every slide.
Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).
3. Unpack: python scripts/office/unpack.py template.pptx unpacked/
4. Build presentation (do this yourself, not with subagents):
- Delete unwanted slides (remove from
<p:sldIdLst>) - Duplicate slides you want to reuse (
add_slide.py) - Reorder slides in
<p:sldIdLst> - Complete all structural changes before step 5
5. Edit content: Update text in each slide{N}.xml. Use subagents here if available — slides are separate XML files, so subagents can edit in parallel.
6. Clean: python scripts/clean.py unpacked/
7. Pack: python scripts/office/pack.py unpacked/ output.pptx --original template.pptx
---
Scripts
| Script | Purpose |
|---|---|
unpack.py | Extract and pretty-print PPTX |
add_slide.py | Duplicate slide or create from layout |
clean.py | Remove orphaned files |
pack.py | Repack with validation |
thumbnail.py | Create visual grid of slides |
unpack.py
python scripts/office/unpack.py input.pptx unpacked/Extracts PPTX, pretty-prints XML, escapes smart quotes.
add_slide.py
python scripts/add_slide.py unpacked/ slide2.xml # Duplicate slide
python scripts/add_slide.py unpacked/ slideLayout2.xml # From layoutPrints <p:sldId> to add to <p:sldIdLst> at desired position.
clean.py
python scripts/clean.py unpacked/Removes slides not in <p:sldIdLst>, unreferenced media, orphaned rels.
pack.py
python scripts/office/pack.py unpacked/ output.pptx --original input.pptxValidates, repairs, condenses XML, re-encodes smart quotes.
thumbnail.py
python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]Creates thumbnails.jpg with slide filenames as labels. Default 3 columns, max 12 per grid.
Use for template analysis only (choosing layouts). For visual QA, use soffice + pdftoppm to create full-resolution individual slide images—see SKILL.md.
---
Slide Operations
Slide order is in ppt/presentation.xml → <p:sldIdLst>.
Reorder: Rearrange <p:sldId> elements.
Delete: Remove <p:sldId>, then run clean.py.
Add: Use add_slide.py. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.
---
Editing Content
Subagents: If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:
- The slide file path(s) to edit
- "Use the Edit tool for all changes"
- The formatting rules and common pitfalls below
For each slide: 1. Read the slide's XML 2. Identify ALL placeholder content—text, images, charts, icons, captions 3. Replace each placeholder with final content
Use the Edit tool, not sed or Python scripts. The Edit tool forces specificity about what to replace and where, yielding better reliability.
Formatting Rules
- Bold all headers, subheadings, and inline labels: Use
b="1"on<a:rPr>. This includes: - Slide titles
- Section headers within a slide
- Inline labels like (e.g.: "Status:", "Description:") at the start of a line
- Never use unicode bullets (•): Use proper list formatting with
<a:buChar>or<a:buAutoNum> - Bullet consistency: Let bullets inherit from the layout. Only specify
<a:buChar>or<a:buNone>.
---
Common Pitfalls
Template Adaptation
When source content has fewer items than the template:
- Remove excess elements entirely (images, shapes, text boxes), don't just clear text
- Check for orphaned visuals after clearing text content
- Run visual QA to catch mismatched counts
When replacing text with different length content:
- Shorter replacements: Usually safe
- Longer replacements: May overflow or wrap unexpectedly
- Test with visual QA after text changes
- Consider truncating or splitting content to fit the template's design constraints
Template slots ≠ Source items: If template has 4 team members but source has 3 users, delete the 4th member's entire group (image + text boxes), not just the text.
Multi-Item Content
If source has multiple items (numbered lists, multiple sections), create separate <a:p> elements for each — never concatenate into one string.
❌ WRONG — all items in one paragraph:
<a:p>
<a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r>
</a:p>✅ CORRECT — separate paragraphs with bold headers:
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r>
</a:p>
<!-- continue pattern -->Copy <a:pPr> from the original paragraph to preserve line spacing. Use b="1" on headers.
Smart Quotes
Handled automatically by unpack/pack. But the Edit tool converts smart quotes to ASCII.
When adding new text with quotes, use XML entities:
<a:t>the “Agreement”</a:t>| Character | Name | Unicode | XML Entity |
|---|---|---|---|
“ | Left double quote | U+201C | “ |
” | Right double quote | U+201D | ” |
‘ | Left single quote | U+2018 | ‘ |
’ | Right single quote | U+2019 | ’ |
Other
- Whitespace: Use
xml:space="preserve"on<a:t>with leading/trailing spaces - XML parsing: Use
defusedxml.minidom, notxml.etree.ElementTree(corrupts namespaces)
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
elementFormDefault="qualified"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:element name="lockedCanvas" type="a:CT_GvmlGroupShape"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="urn:schemas-microsoft-com:office:powerpoint"
targetNamespace="urn:schemas-microsoft-com:office:powerpoint" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="iscomment" type="CT_Empty"/>
<xsd:element name="textdata" type="CT_Rel"/>
<xsd:complexType name="CT_Empty"/>
<xsd:complexType name="CT_Rel">
<xsd:attribute name="id" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>