Skip to content

Commit 3021dc6

Browse files
committed
feat(providers): add Oracle Cloud Infrastructure provider
Implements an OCI Compute provider that launches, removes, and lists Woodpecker agent instances using the official oci-go-sdk/v65. Authentication supports both explicit API key credentials via flags and the SDK default config chain (~/.oci/config, instance principal). Pool membership is tracked via OCI freeform tags. ListInstances pagination is handled transparently. Flex shape OCPU/memory is configurable.
1 parent 9989c83 commit 3021dc6

6 files changed

Lines changed: 663 additions & 2 deletions

File tree

cmd/woodpecker-autoscaler/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"go.woodpecker-ci.org/autoscaler/engine/types"
1818
"go.woodpecker-ci.org/autoscaler/providers/aws"
1919
"go.woodpecker-ci.org/autoscaler/providers/hetznercloud"
20+
"go.woodpecker-ci.org/autoscaler/providers/oracle"
2021
"go.woodpecker-ci.org/autoscaler/providers/scaleway"
2122
"go.woodpecker-ci.org/autoscaler/providers/vultr"
2223
"go.woodpecker-ci.org/autoscaler/server"
@@ -29,6 +30,8 @@ func setupProvider(ctx context.Context, cmd *cli.Command, config *config.Config)
2930
return aws.New(ctx, cmd, config)
3031
case "hetznercloud":
3132
return hetznercloud.New(ctx, cmd, config)
33+
case "oracle":
34+
return oracle.New(ctx, cmd, config)
3235
// TODO: Temp disabled due to the security issue https://github.com/woodpecker-ci/autoscaler/issues/91
3336
// Enable it again when the issue is fixed.
3437
// case "linode":
@@ -168,6 +171,7 @@ func main() {
168171
// Enable it again when the issue is fixed.
169172
// app.Flags = append(app.Flags, linode.ProviderFlags...)
170173
app.Flags = append(app.Flags, aws.ProviderFlags...)
174+
app.Flags = append(app.Flags, oracle.ProviderFlags...)
171175
app.Flags = append(app.Flags, vultr.ProviderFlags...)
172176

173177
if err := app.Run(context.Background(), os.Args); err != nil {

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/hetznercloud/hcloud-go/v2 v2.39.0
1313
github.com/joho/godotenv v1.5.1
1414
github.com/linode/linodego v1.68.0
15+
github.com/oracle/oci-go-sdk/v65 v65.114.0
1516
github.com/rs/zerolog v1.35.1
1617
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36
1718
github.com/stretchr/testify v1.11.1
@@ -40,6 +41,7 @@ require (
4041
github.com/cespare/xxhash/v2 v2.3.0 // indirect
4142
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
4243
github.com/go-resty/resty/v2 v2.17.2 // indirect
44+
github.com/gofrs/flock v0.10.0 // indirect
4345
github.com/google/go-querystring v1.2.0 // indirect
4446
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
4547
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
@@ -51,8 +53,11 @@ require (
5153
github.com/prometheus/client_model v0.6.2 // indirect
5254
github.com/prometheus/common v0.66.1 // indirect
5355
github.com/prometheus/procfs v0.16.1 // indirect
56+
github.com/sony/gobreaker/v2 v2.4.0 // indirect
5457
github.com/stretchr/objx v0.5.2 // indirect
58+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
5559
go.yaml.in/yaml/v2 v2.4.3 // indirect
60+
golang.org/x/crypto v0.50.0 // indirect
5661
golang.org/x/sys v0.43.0 // indirect
5762
golang.org/x/text v0.36.0 // indirect
5863
google.golang.org/protobuf v1.36.11 // indirect

go.sum

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
4242
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
4343
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
4444
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
45+
github.com/gofrs/flock v0.10.0 h1:SHMXenfaB03KbroETaCMtbBg3Yn29v4w1r+tgy4ff4k=
46+
github.com/gofrs/flock v0.10.0/go.mod h1:FirDy1Ing0mI2+kB6wk+vyyAH+e6xiE+EYA0jnzV9jc=
4547
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
4648
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
4749
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
@@ -75,6 +77,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
7577
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
7678
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
7779
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
80+
github.com/oracle/oci-go-sdk/v65 v65.114.0 h1:7LvSJwXebrQ/iasML0ff1wcVN38rE0ZMzRo2Zg6dhjA=
81+
github.com/oracle/oci-go-sdk/v65 v65.114.0/go.mod h1:oo33NDf2XPqx3/N6oLG4jFlrqJ0xu4Rlt9SfuAbtDFs=
7882
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7983
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
8084
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -86,12 +90,14 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z
8690
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
8791
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
8892
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
89-
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
90-
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
93+
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
94+
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
9195
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
9296
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
9397
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo=
9498
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM=
99+
github.com/sony/gobreaker/v2 v2.4.0 h1:g2KJRW1Ubty3+ZOcSEUN7K+REQJdN6yo6XvaML+jptg=
100+
github.com/sony/gobreaker/v2 v2.4.0/go.mod h1:pTyFJgcZ3h2tdQVLZZruK2C0eoFL1fb/G83wK1ZQl+s=
95101
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
96102
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
97103
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -106,6 +112,8 @@ github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI=
106112
github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
107113
github.com/vultr/govultr/v3 v3.31.1 h1:AoJRZ0WDS1J1otp2wk3OD4aYh4EQxFU+kvyOPdCe4+Y=
108114
github.com/vultr/govultr/v3 v3.31.1/go.mod h1:2zyUw9yADQaGwKnwDesmIOlBNLrm7edsCfWHFJpWKf8=
115+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
116+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
109117
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
110118
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
111119
go.woodpecker-ci.org/woodpecker/v3 v3.13.0 h1:XSokm3nwTbUJTUgf7uQ1zh/BYj3G6n6cTFprQUbpw8M=
@@ -114,6 +122,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
114122
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
115123
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
116124
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
125+
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
126+
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
117127
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
118128
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
119129
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=

providers/oracle/flags.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package oracle
2+
3+
import (
4+
"os"
5+
6+
"github.com/urfave/cli/v3"
7+
)
8+
9+
const category = "Oracle Cloud"
10+
11+
var ProviderFlags = []cli.Flag{
12+
// Authentication — either all four explicit fields or none (falls back to ~/.oci/config).
13+
&cli.StringFlag{
14+
Name: "oracle-tenancy-ocid",
15+
Usage: "Tenancy OCID for OCI API authentication",
16+
Sources: cli.NewValueSourceChain(
17+
cli.EnvVar("WOODPECKER_ORACLE_TENANCY_OCID"),
18+
cli.File(os.Getenv("WOODPECKER_ORACLE_TENANCY_OCID_FILE")),
19+
),
20+
Category: category,
21+
},
22+
&cli.StringFlag{
23+
Name: "oracle-user-ocid",
24+
Usage: "User OCID for OCI API authentication",
25+
Sources: cli.NewValueSourceChain(
26+
cli.EnvVar("WOODPECKER_ORACLE_USER_OCID"),
27+
cli.File(os.Getenv("WOODPECKER_ORACLE_USER_OCID_FILE")),
28+
),
29+
Category: category,
30+
},
31+
&cli.StringFlag{
32+
Name: "oracle-fingerprint",
33+
Usage: "API key fingerprint for OCI API authentication",
34+
Sources: cli.NewValueSourceChain(
35+
cli.EnvVar("WOODPECKER_ORACLE_FINGERPRINT"),
36+
cli.File(os.Getenv("WOODPECKER_ORACLE_FINGERPRINT_FILE")),
37+
),
38+
Category: category,
39+
},
40+
&cli.StringFlag{
41+
Name: "oracle-private-key-file",
42+
Usage: "Path to the PEM-encoded RSA private key for OCI API authentication",
43+
Sources: cli.EnvVars("WOODPECKER_ORACLE_PRIVATE_KEY_FILE"),
44+
Category: category,
45+
},
46+
&cli.StringFlag{
47+
Name: "oracle-region",
48+
Usage: "OCI region identifier (e.g. us-ashburn-1)",
49+
Sources: cli.EnvVars("WOODPECKER_ORACLE_REGION"),
50+
Category: category,
51+
},
52+
// Compute placement
53+
&cli.StringFlag{
54+
Name: "oracle-compartment-id",
55+
Usage: "Compartment OCID in which to launch agent instances",
56+
Sources: cli.EnvVars("WOODPECKER_ORACLE_COMPARTMENT_ID"),
57+
Category: category,
58+
},
59+
&cli.StringFlag{
60+
Name: "oracle-availability-domain",
61+
Usage: "Availability domain name (e.g. IiCz:US-ASHBURN-AD-1)",
62+
Sources: cli.EnvVars("WOODPECKER_ORACLE_AVAILABILITY_DOMAIN"),
63+
Category: category,
64+
},
65+
&cli.StringFlag{
66+
Name: "oracle-subnet-id",
67+
Usage: "Subnet OCID for agent instance network interfaces",
68+
Sources: cli.EnvVars("WOODPECKER_ORACLE_SUBNET_ID"),
69+
Category: category,
70+
},
71+
// Instance configuration
72+
&cli.StringFlag{
73+
Name: "oracle-image-id",
74+
Usage: "OCID of the base image for agent instances",
75+
Sources: cli.EnvVars("WOODPECKER_ORACLE_IMAGE_ID"),
76+
Category: category,
77+
},
78+
&cli.StringFlag{
79+
Name: "oracle-shape",
80+
Usage: "Instance shape (e.g. VM.Standard.E4.Flex)",
81+
Sources: cli.EnvVars("WOODPECKER_ORACLE_SHAPE"),
82+
Value: "VM.Standard.E4.Flex",
83+
Category: category,
84+
},
85+
&cli.FloatFlag{
86+
Name: "oracle-shape-ocpus",
87+
Usage: "Number of OCPUs to allocate (only applies to flexible shapes)",
88+
Sources: cli.EnvVars("WOODPECKER_ORACLE_SHAPE_OCPUS"),
89+
Value: 1,
90+
Category: category,
91+
},
92+
&cli.FloatFlag{
93+
Name: "oracle-shape-memory-gbs",
94+
Usage: "Amount of memory in GB to allocate (only applies to flexible shapes)",
95+
Sources: cli.EnvVars("WOODPECKER_ORACLE_SHAPE_MEMORY_GBS"),
96+
Value: 6,
97+
Category: category,
98+
},
99+
&cli.StringFlag{
100+
Name: "oracle-ssh-authorized-key",
101+
Usage: "SSH public key to inject into agent instances",
102+
Sources: cli.EnvVars("WOODPECKER_ORACLE_SSH_AUTHORIZED_KEY"),
103+
Category: category,
104+
},
105+
}

0 commit comments

Comments
 (0)