Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage: Add Oracle Cloud Infrastructure Object Storage Bucket support #4661

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Expand Up @@ -35,7 +35,7 @@ jobs:
- run:
name: "Run unit tests."
environment:
THANOS_TEST_OBJSTORE_SKIP: AZURE,COS,ALIYUNOSS,BOS
THANOS_TEST_OBJSTORE_SKIP: AZURE,COS,ALIYUNOSS,BOS,OCI
# Variables for Swift testing.
OS_AUTH_URL: http://127.0.0.1:5000/v2.0
OS_PASSWORD: s3cr3t
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Expand Up @@ -288,12 +288,12 @@ test: export THANOS_TEST_PROMETHEUS_PATHS= $(PROMETHEUS_ARRAY)
test: export THANOS_TEST_ALERTMANAGER_PATH= $(ALERTMANAGER)
test: check-git install-deps
@echo ">> install thanos GOOPTS=${GOOPTS}"
@echo ">> running unit tests (without /test/e2e). Do export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS if you want to skip e2e tests against all real store buckets. Current value: ${THANOS_TEST_OBJSTORE_SKIP}"
@echo ">> running unit tests (without /test/e2e). Do export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS,OCI if you want to skip e2e tests against all real store buckets. Current value: ${THANOS_TEST_OBJSTORE_SKIP}"
@go test $(shell go list ./... | grep -v /vendor/ | grep -v /test/e2e);

.PHONY: test-local
test-local: ## Runs test excluding tests for ALL object storage integrations.
test-local: export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS
test-local: export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS,OCI
test-local:
$(MAKE) test

Expand All @@ -311,7 +311,7 @@ test-e2e: docker $(GOTESPLIT)

.PHONY: test-e2e-local
test-e2e-local: ## Runs all thanos e2e tests locally.
test-e2e-local: export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS
test-e2e-local: export THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS,OCI
test-e2e-local:
$(MAKE) test-e2e

Expand Down
82 changes: 71 additions & 11 deletions docs/storage.md
Expand Up @@ -37,15 +37,16 @@ In Kubernetes it is as easy as (on Thanos sidecar example):

Current object storage client implementations:

| Provider | Maturity | Aimed For | Auto-tested on CI | Maintainers |
|----------------------------------------------------------------------------------------|--------------------|-----------------------|-------------------|-------------------------|
| [Google Cloud Storage](#gcs) | Stable | Production Usage | yes | @bwplotka |
| [AWS/S3](#s3) (and all S3-compatible storages e.g disk-based [Minio](https://min.io/)) | Stable | Production Usage | yes | @bwplotka |
| [Azure Storage Account](#azure) | Stable | Production Usage | no | @vglafirov |
| [OpenStack Swift](#openstack-swift) | Beta (working PoC) | Production Usage | yes | @FUSAKLA |
| [Tencent COS](#tencent-cos) | Beta | Production Usage | no | @jojohappy,@hanjm |
| [AliYun OSS](#aliyun-oss) | Beta | Production Usage | no | @shaulboozhiao,@wujinhu |
| [Local Filesystem](#filesystem) | Stable | Testing and Demo only | yes | @bwplotka |
| Provider | Maturity | Aimed For | Auto-tested on CI | Maintainers |
|-------------------------------------------------------------------------------------------|--------------------|-----------------------|-------------------|----------------------------------|
| [Google Cloud Storage](#gcs) | Stable | Production Usage | yes | @bwplotka |
| [AWS/S3](#s3) (and all S3-compatible storages e.g disk-based [Minio](https://min.io/)) | Stable | Production Usage | yes | @bwplotka |
| [Azure Storage Account](#azure) | Stable | Production Usage | no | @vglafirov |
| [OpenStack Swift](#openstack-swift) | Beta (working PoC) | Production Usage | yes | @FUSAKLA |
| [Tencent COS](#tencent-cos) | Beta | Production Usage | no | @jojohappy,@hanjm |
| [AliYun OSS](#aliyun-oss) | Beta | Production Usage | no | @shaulboozhiao,@wujinhu |
| [Local Filesystem](#filesystem) | Stable | Testing and Demo only | yes | @bwplotka |
| [Oracle Cloud Infrastructure Object Storage](#oracle-cloud-infrastructure-object-storage) | Beta | Production Usage | yes | @aarontams,@gaurav-05,@ericrrath |

**Missing support to some object storage?** Check out [how to add your client section](#how-to-add-a-new-client-to-thanos)

Expand Down Expand Up @@ -207,7 +208,7 @@ Example working AWS IAM policy for user:
To test the policy, set env vars for S3 access for *empty, not used* bucket as well as:

```
THANOS_TEST_OBJSTORE_SKIP=GCS,AZURE,SWIFT,COS,ALIYUNOSS
THANOS_TEST_OBJSTORE_SKIP=GCS,AZURE,SWIFT,COS,ALIYUNOSS,OCI
THANOS_ALLOW_EXISTING_BUCKET_USE=true
```

Expand Down Expand Up @@ -241,7 +242,7 @@ We need access to CreateBucket and DeleteBucket and access to all buckets:
}
```

With this policy you should be able to run set `THANOS_TEST_OBJSTORE_SKIP=GCS,AZURE,SWIFT,COS,ALIYUNOSS` and unset `S3_BUCKET` and run all tests using `make test`.
With this policy you should be able to run set `THANOS_TEST_OBJSTORE_SKIP=GCS,AZURE,SWIFT,COS,ALIYUNOSS,OCI` and unset `S3_BUCKET` and run all tests using `make test`.

Details about AWS policies: https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html

Expand Down Expand Up @@ -493,6 +494,65 @@ config:
prefix: ""
```

### Oracle Cloud Infrastructure Object Storage

To configure Oracle Cloud Infrastructure (OCI) Object Storage as Thanos Object Store, you need to provide appropriate authentication credentials to your OCI tenancy. The OCI object storage client implementation for Thanos supports either the default keypair or instance principal authentication.

#### API Signing Key
The default API signing key authentication provider leverages same [configuration as the OCI CLI](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cliconcepts.htm) which is usually stored in at `$HOME/.oci/config` or via variable names starting with the string `OCI_CLI`. You can also use environment variables that start with `TF_VAR`. If the same configuration is found in multiple places the provider will prefer the first one.

The following example configures the provider to look for an existing API signing key for authentication:
```yaml
type: OCI
config:
provider: "default"
bucket: ""
compartment_ocid: ""
part_size: "" // Optional part size to override the OCI default of 128 MiB, value is in bytes.
max_request_retries: "" // Optional maximum number of retries for a request.
request_retry_interval: "" // Optional sleep duration in seconds between retry requests.
http_config:
idle_conn_timeout: 1m30s // Optional maximum amount of time an idle (keep-alive) connection will remain idle before closing itself. Zero means no limit.
response_header_timeout: 2m // Optional amount of time to wait for a server's response headers after fully writing the request.
tls_handshake_timeout: 10s // Optional maximum amount of time waiting to wait for a TLS handshake. Zero means no timeout.
expect_continue_timeout: 1s // Optional amount of time to wait for a server's first response headers. Zero means no timeout and causes the body to be sent immediately.
insecure_skip_verify: false // Optional. If true, crypto/tls accepts any certificate presented by the server and any host name in that certificate.
max_idle_conns: 100 // Optional maximum number of idle (keep-alive) connections across all hosts. Zero means no limit.
max_idle_conns_per_host: 100 // Optional maximum idle (keep-alive) connections to keep per-host. If zero, DefaultMaxIdleConnsPerHost=2 is used.
max_conns_per_host: 0 // Optional maximum total number of connections per host.
disable_compression: false // Optional. If true, prevents the Transport from requesting compression.
client_timeout: 90s // Optional time limit for requests made by the HTTP Client.
```


Comment on lines +526 to +527

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Alternatively, you can provide API signing key authentication parameters in the configuration:
```yaml
type: OCI
config:
provider: "raw"
bucket: "thanos" // name of the object storage bucket
compartment_ocid: "ocid1.compartment.oc1..." // compartment in which the object storage bucket was created
tenancy_ocid: "ocid1.tenancy.oc1..."
user_ocid: "ocid1.user.oc1..."
region: "us-ashburn-1"
fingerprint: "aa:a1:bb:b1:cc:c1:dd:d1:ee:e1:ff:f1:aa:a2:bb:b2"
privatekey: "/path/to/oci_api_key.pem"
passphrase: "" // Optional passphrase used to encrypt the private API Signing key

#### Instance Principal Provider
For Example:
Comment on lines +528 to +529

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Instance Principal Provider
For Example:
#### Instance Principal authentication
Instance principal authentication is available when the provider is running on a compute instance within Oracle Cloud Infrastructure. Each compute instance has its own identity, and it authenticates using the certificates that are added to it. These certificates are automatically created, assigned to instances and rotated, preventing the need for you to distribute credentials to your hosts and rotate them. You are required to [configure an appropriate Dynamic Group and assign that group permissions via policies](https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm) so that the compute instance is authorised to access the object storage bucket.
The following configuration example enables instance principal authentication:

```yaml
type: OCI
config:
provider: "instance-principal"
bucket: ""
compartment_ocid: ""
```
You can also include any of the optional configuration just like the example in `Default Provider`.

#### Raw Provider
For Example:
```yaml
type: OCI
config:
provider: "raw"
bucket: ""
compartment_ocid: ""
tenancy_ocid: ""
user_ocid: ""
region: ""
fingerprint: ""
privatekey: ""
passphrase: "" // Optional passphrase to encrypt the private API Signing key
```
You can also include any of the optional configuration just like the example in `Default Provider`.

### How to add a new client to Thanos?

Following checklist allows adding new Go code client to supported providers:
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Expand Up @@ -60,6 +60,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/opentracing/basictracer-go v1.0.0
github.com/opentracing/opentracing-go v1.2.0
github.com/oracle/oci-go-sdk/v65 v65.13.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
github.com/prometheus/alertmanager v0.23.1-0.20210914172521-e35efbddb66a
Expand Down Expand Up @@ -150,6 +151,7 @@ require (
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
github.com/gobwas/pool v0.2.0 // indirect
github.com/gobwas/ws v1.0.2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/googleapis v1.4.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
Expand Down Expand Up @@ -189,7 +191,7 @@ require (
github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect
github.com/sercand/kuberesolver v2.4.0+incompatible // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/sony/gobreaker v0.4.1 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/weaveworks/promrus v1.2.0 // indirect
Expand Down
7 changes: 6 additions & 1 deletion go.sum
Expand Up @@ -867,6 +867,8 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
Expand Down Expand Up @@ -1540,6 +1542,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
github.com/oracle/oci-go-sdk/v65 v65.13.0 h1:0+9ea5goYfhI3/MPfbIQU6yzHYWE6sCk6VuUepxk5Nk=
github.com/oracle/oci-go-sdk/v65 v65.13.0/go.mod h1:oyMrMa1vOzzKTmPN+kqrTR9y9kPA2tU1igN3NUSNTIE=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
Expand Down Expand Up @@ -1738,8 +1742,9 @@ github.com/snowflakedb/gosnowflake v1.3.13/go.mod h1:6nfka9aTXkUNha1p1cjeeyjDvcy
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
Expand Down
4 changes: 4 additions & 0 deletions pkg/objstore/client/factory.go
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/thanos-io/thanos/pkg/objstore/cos"
"github.com/thanos-io/thanos/pkg/objstore/filesystem"
"github.com/thanos-io/thanos/pkg/objstore/gcs"
"github.com/thanos-io/thanos/pkg/objstore/oci"
"github.com/thanos-io/thanos/pkg/objstore/oss"
"github.com/thanos-io/thanos/pkg/objstore/s3"
"github.com/thanos-io/thanos/pkg/objstore/swift"
Expand All @@ -36,6 +37,7 @@ const (
COS ObjProvider = "COS"
ALIYUNOSS ObjProvider = "ALIYUNOSS"
BOS ObjProvider = "BOS"
OCI ObjProvider = "OCI"
)

type BucketConfig struct {
Expand Down Expand Up @@ -76,6 +78,8 @@ func NewBucket(logger log.Logger, confContentYaml []byte, reg prometheus.Registe
bucket, err = filesystem.NewBucketFromConfig(config)
case string(BOS):
bucket, err = bos.NewBucket(logger, config, component)
case string(OCI):
bucket, err = oci.NewBucket(logger, config)
default:
return nil, errors.Errorf("bucket with type %s is not supported", bucketConf.Type)
}
Expand Down
17 changes: 16 additions & 1 deletion pkg/objstore/objtesting/foreach.go
Expand Up @@ -17,14 +17,15 @@ import (
"github.com/thanos-io/thanos/pkg/objstore/azure"
"github.com/thanos-io/thanos/pkg/objstore/cos"
"github.com/thanos-io/thanos/pkg/objstore/gcs"
"github.com/thanos-io/thanos/pkg/objstore/oci"
"github.com/thanos-io/thanos/pkg/objstore/oss"
"github.com/thanos-io/thanos/pkg/objstore/s3"
"github.com/thanos-io/thanos/pkg/objstore/swift"
"github.com/thanos-io/thanos/pkg/testutil"
)

// IsObjStoreSkipped returns true if given provider ID is found in THANOS_TEST_OBJSTORE_SKIP array delimited by comma e.g:
// THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS.
// THANOS_TEST_OBJSTORE_SKIP=GCS,S3,AZURE,SWIFT,COS,ALIYUNOSS,BOS,OCI.
func IsObjStoreSkipped(t *testing.T, provider client.ObjProvider) bool {
if e, ok := os.LookupEnv("THANOS_TEST_OBJSTORE_SKIP"); ok {
obstores := strings.Split(e, ",")
Expand Down Expand Up @@ -170,4 +171,18 @@ func ForeachStore(t *testing.T, testFn func(t *testing.T, bkt objstore.Bucket))
testFn(t, objstore.NewPrefixedBucket(bkt, "some_prefix"))
})
}

// Optional OCI.
if !IsObjStoreSkipped(t, client.OCI) {
t.Run("oci", func(t *testing.T) {
bkt, closeFn, err := oci.NewTestBucket(t)
testutil.Ok(t, err)

t.Parallel()
defer closeFn()

testFn(t, bkt)
})
}

}