// 2019 Rackspace, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package tools import ( "fmt" "io" "net/http" "strings" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects" "github.com/sirupsen/logrus" "github.rackspace.com/gorax/clients/passwordsafe" ) type ( // ObjectStore type represents the data needed to initialize // an RS Cloud ObjectStore service. ObjectStore struct { *gophercloud.ServiceClient Region string Container string } // Object is the type representation of a data-object to // get/push to the object-store. Object struct { Name string `json:"name"` ContentType string `json:"content_type"` Hash string `json:"hash"` LastModified string `json:"last_modified"` Bytes float64 `json:"bytes"` } ) const ( objRegion = "ORD" objContainer = "Site_Files" ) // ObjectService function takes a passwordsafe client and initializes a v1 storage // client to connect to RS Cloud services. func ObjectService(k passwordsafe.Credential) (obj ObjectStore, err error) { provider, err := openstack.AuthenticatedClient(gophercloud.AuthOptions{ IdentityEndpoint: "https://identity.api.rackspacecloud.com/v2.0", Username: k.Credential.Username, Password: k.Credential.Password, }) if err != nil { return } service, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{Region: objRegion}) if err != nil { return } return ObjectStore{ServiceClient: service, Region: objRegion, Container: objContainer}, nil } // Create method takes an ObjectStore receiver, and will create a new object within the // RS Cloud service in the object-store func (o ObjectStore) Create(objectName, noteID string, content io.Reader) error { obj := objects.CreateOpts{ Content: content, Metadata: map[string]string{ "noteId": noteID, }, } r := objects.Create(o.ServiceClient, o.Container, fmt.Sprintf("%s-%s", noteID, objectName), obj) return r.Err } // Delete method takes an ObjectStore receiver, and will delete a specified object by name within the // RS Cloud service in the object-store func (o ObjectStore) Delete(objectName, noteID string) error { obj := objects.DeleteOpts{} r := objects.Delete(o.ServiceClient, o.Container, fmt.Sprintf("%s-%s", noteID, objectName), obj) return r.Err } // Get method takes an ObjectStore receiver, and will get an object within the // RS Cloud service in the object-store func (o ObjectStore) Get(objectName, noteID string) ([]byte, http.Header, error) { obj := objects.DownloadOpts{} d := objects.Download(o.ServiceClient, o.Container, fmt.Sprintf("%s-%s", noteID, objectName), obj) content, err := d.ExtractContent() logrus.Infof("GET - %s %s bytes of type %s", objectName, d.Header.Get("Content-Length"), d.Header.Get("Content-Type")) return content, d.Header, err } // List method takes an ObjectStore receiver, and will return a listing of all the objects that // exist in the object-store func (o ObjectStore) List(noteID string) ([]Object, error) { obj := objects.ListOpts{ Full: true, Prefix: noteID, } pages, err := objects.List(o.ServiceClient, o.Container, obj).AllPages() if err != nil { return nil, err } var returnData = make([]Object, 0) if body, ok := pages.GetBody().([]interface{}); ok { for _, elem := range body { // spew.Dump(elem) o := Object{} if data, ok := elem.(map[string]interface{}); ok { if e, ok := data["name"].(string); ok { o.Name = strings.TrimPrefix(e, fmt.Sprintf("%s-", noteID)) } if e, ok := data["content_type"].(string); ok { o.ContentType = e } if e, ok := data["last_modified"].(string); ok { o.LastModified = e } if e, ok := data["hash"].(string); ok { o.Hash = e } if e, ok := data["bytes"].(float64); ok { o.Bytes = e } returnData = append(returnData, o) } } } return returnData, nil }