Skip to content

Commit ddb1a2c

Browse files
committed
feat(ovh_cloud_project_storage_s3_presign): add resource
Use this resource to presign url to interact with s3 fast storage. This can be used for multiple uses-cases like uploading a post-install script to s3 then passing the URL to a dedicated_server install task. The URL is signed for a fixed period, hence the `expire` parameter. Signed-off-by: Arnaud SINAYS <[email protected]>
1 parent 03b3ced commit ddb1a2c

6 files changed

+249
-0
lines changed

ovh/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func Provider() *schema.Provider {
139139
"ovh_cloud_project_kube_iprestrictions": resourceCloudProjectKubeIpRestrictions(),
140140
"ovh_cloud_project_network_private": resourceCloudProjectNetworkPrivate(),
141141
"ovh_cloud_project_network_private_subnet": resourceCloudProjectNetworkPrivateSubnet(),
142+
"ovh_cloud_project_region_storage_presign": resourceCloudProjectRegionStoragePresign(),
142143
"ovh_cloud_project_user": resourceCloudProjectUser(),
143144
"ovh_cloud_project_user_s3_credential": resourceCloudProjectUserS3Credential(),
144145
"ovh_cloud_project_user_s3_policy": resourceCloudProjectUserS3Policy(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
6+
"github.com/ovh/terraform-provider-ovh/ovh/helpers"
7+
"net/url"
8+
"strconv"
9+
"time"
10+
)
11+
12+
func resourceCloudProjectRegionStoragePresign() *schema.Resource {
13+
return &schema.Resource{
14+
Create: resourceCloudProjectRegionStoragePresignCreate,
15+
Read: schema.Noop,
16+
Delete: schema.Noop,
17+
18+
Schema: map[string]*schema.Schema{
19+
"service_name": {
20+
Type: schema.TypeString,
21+
Required: true,
22+
ForceNew: true,
23+
DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil),
24+
Description: "Service name of the resource representing the ID of the cloud project.",
25+
},
26+
"region_name": {
27+
Type: schema.TypeString,
28+
Required: true,
29+
ForceNew: true,
30+
Description: "Region name.",
31+
},
32+
"name": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
ForceNew: true,
36+
Description: "The S3 storage container's name.",
37+
},
38+
"expire": {
39+
Type: schema.TypeInt,
40+
Required: true,
41+
ForceNew: true,
42+
Description: "How long (in seconds) the URL will be valid.",
43+
},
44+
"method": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
ForceNew: true,
48+
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
49+
err := helpers.ValidateStringEnum(v.(string), []string{"GET", "PUT"})
50+
if err != nil {
51+
errors = append(errors, err)
52+
}
53+
return
54+
},
55+
},
56+
"object": {
57+
Type: schema.TypeString,
58+
Required: true,
59+
ForceNew: true,
60+
Description: "Name of the object to download or upload.",
61+
},
62+
63+
// Computed
64+
"url": {
65+
Type: schema.TypeString,
66+
Computed: true,
67+
Description: "Presigned URL.",
68+
},
69+
},
70+
}
71+
}
72+
73+
func resourceCloudProjectRegionStoragePresignCreate(d *schema.ResourceData, meta interface{}) error {
74+
config := meta.(*Config)
75+
serviceName := d.Get("service_name").(string)
76+
regionName := d.Get("region_name").(string)
77+
name := d.Get("name").(string)
78+
79+
resp := &PresignedURL{}
80+
opts := (&PresignedURLInput{}).FromResource(d)
81+
82+
endpoint := fmt.Sprintf("/cloud/project/%s/region/%s/storage/%s/presign", url.PathEscape(serviceName), url.PathEscape(regionName), url.PathEscape(name))
83+
if err := config.OVHClient.Post(endpoint, opts, resp); err != nil {
84+
return fmt.Errorf("Error calling post %s:\n\t %q", endpoint, err)
85+
}
86+
d.SetId(strconv.FormatInt(time.Now().Unix(), 10))
87+
err := d.Set("url", resp.URL)
88+
if err != nil {
89+
return err
90+
}
91+
return nil
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
6+
"os"
7+
"testing"
8+
)
9+
10+
const testCloudProjectRegionStoragePresign = `
11+
resource "ovh_cloud_project_region_storage_presign" "presign_url" {
12+
service_name = "%s"
13+
region_name = "%s"
14+
name = "%s"
15+
expire = 3600
16+
method = "GET"
17+
object = "%s"
18+
}
19+
`
20+
21+
func testAccPreCheckCloudRegionStorage(t *testing.T) {
22+
testAccPreCheckCredentials(t)
23+
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_STORAGE_REGION_TEST")
24+
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_STORAGE_BUCKET_NAME_TEST")
25+
checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_STORAGE_OBJECT_TEST")
26+
}
27+
28+
func testAccCheckCloudRegionStorage(t *testing.T) {
29+
30+
type cloudProjectRegionStorageResponse struct {
31+
Name string `json:"name"`
32+
Region string `json:"region"`
33+
}
34+
35+
r := cloudProjectRegionStorageResponse{}
36+
37+
endpoint := fmt.Sprintf("/cloud/project/%s/region/%s/storage/%s",
38+
os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST"),
39+
os.Getenv("OVH_CLOUD_PROJECT_STORAGE_REGION_TEST"),
40+
os.Getenv("OVH_CLOUD_PROJECT_STORAGE_BUCKET_NAME_TEST"))
41+
42+
err := testAccOVHClient.Get(endpoint, &r)
43+
if err != nil {
44+
t.Fatalf("Error: %q\n", err)
45+
}
46+
t.Logf("Read Storage Container %s -> name: '%s', region: '%s'", endpoint, r.Name, r.Region)
47+
}
48+
49+
func TestCloudProjectRegionStoragePresign(t *testing.T) {
50+
serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST")
51+
regionName := os.Getenv("OVH_CLOUD_PROJECT_STORAGE_REGION_TEST")
52+
name := os.Getenv("OVH_CLOUD_PROJECT_STORAGE_BUCKET_NAME_TEST")
53+
object := os.Getenv("OVH_CLOUD_PROJECT_STORAGE_OBJECT_TEST")
54+
55+
config := fmt.Sprintf(testCloudProjectRegionStoragePresign, serviceName, regionName, name, object)
56+
57+
resource.Test(t, resource.TestCase{
58+
PreCheck: func() {
59+
testAccPreCheckCloudRegionStorage(t)
60+
testAccPreCheckCloud(t)
61+
testAccCheckCloudProjectExists(t)
62+
testAccCheckCloudRegionStorage(t)
63+
},
64+
Providers: testAccProviders,
65+
Steps: []resource.TestStep{
66+
{
67+
Config: config,
68+
Check: resource.ComposeTestCheckFunc(
69+
resource.TestCheckResourceAttrSet("ovh_cloud_project_region_storage_presign.presign_url", "url"),
70+
),
71+
},
72+
},
73+
})
74+
}

ovh/types_presigned_url.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ovh
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5+
)
6+
7+
type PresignedURL struct {
8+
Method string `json:"method"`
9+
URL string `json:"url"`
10+
}
11+
12+
type PresignedURLInput struct {
13+
Expire int `json:"expire"`
14+
Method string `json:"method"`
15+
Object string `json:"object"`
16+
}
17+
18+
func (opts *PresignedURLInput) FromResource(d *schema.ResourceData) *PresignedURLInput {
19+
opts.Expire = d.Get("expire").(int)
20+
opts.Method = d.Get("method").(string)
21+
opts.Object = d.Get("object").(string)
22+
return opts
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
layout: "ovh"
3+
page_title: "OVH: cloud_project_region_storage_presign"
4+
sidebar_current: "docs-ovh-resource-cloud-project-region-storage-presign"
5+
description: |-
6+
Generates a temporary presigned S3 URLs to download or upload an object.
7+
---
8+
9+
# ovh_cloud_project_region_storage_presign
10+
11+
Generates a temporary presigned S3 URLs to download or upload an object.
12+
13+
-> __NOTE__ This resource is only compatible with the `High Performance - S3` solution for object storage.
14+
15+
## Example Usage
16+
17+
```hcl
18+
resource "ovh_cloud_project_region_storage_presign" "presigned_url" {
19+
service_name = "xxxxxxxxxxxxxxxxx"
20+
region_name = "GRA"
21+
name = "s3-bucket-name"
22+
expire = 3600
23+
method = "GET"
24+
object = "an-object-in-the-bucket"
25+
}
26+
27+
output "presigned_url" {
28+
value = ovh_cloud_project_region_storage_presign.presigned_url.url
29+
}
30+
```
31+
32+
## Argument Reference
33+
34+
The following arguments are supported:
35+
36+
* `service_name` - (Required) The id of the public cloud project. If omitted,
37+
the `OVH_CLOUD_PROJECT_SERVICE` environment variable is used.
38+
* `region_name` - (Required) The region in which your storage is located.
39+
Ex.: "GRA".
40+
* `name` - (Required) The name of your S3 storage container/bucket.
41+
* `expire` - (Required) Define, in seconds, for how long your URL will be valid.
42+
* `method` - (Required) The method you want to use to interact with your object. Can be either 'GET' or 'PUT'.
43+
* `object` - (Required) The name of the object in your S3 bucket.
44+
45+
46+
## Attributes Reference
47+
48+
The following attributes are exported:
49+
50+
* `service_name` - See Argument Reference above.
51+
* `region_name` - See Argument Reference above.
52+
* `name` - See Argument Reference above.
53+
* `expire` - See Argument Reference above.
54+
* `method` - See Argument Reference above.
55+
* `object` - See Argument Reference above.
56+
* `url` - Computed URL result.

website/ovh.erb

+3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@
160160
<li<%= sidebar_current("docs-ovh-resource-cloud-project-network-private-subnet") %>>
161161
<a href="/docs/providers/ovh/r/cloud_project_network_private_subnet.html">ovh_cloud_project_network_private_subnet</a>
162162
</li>
163+
<li<%= sidebar_current("docs-ovh-resource-cloud-project-region-storage-presign") %>>
164+
<a href="/docs/providers/ovh/r/cloud_project_region_storage_presign.html">ovh_cloud_project_region_storage_presign</a>
165+
</li>
163166
<li<%= sidebar_current("docs-ovh-resource-cloud-project-user") %>>
164167
<a href="/docs/providers/ovh/r/cloud_project_user.html">ovh_cloud_project_user</a>
165168
</li>

0 commit comments

Comments
 (0)