Skip to content

Commit

Permalink
Added S3 user management
Browse files Browse the repository at this point in the history
Signed-off-by: utkarshbhatthere <[email protected]>
  • Loading branch information
UtkarshBhatthere committed Jul 11, 2023
1 parent 45d7067 commit 6633df4
Show file tree
Hide file tree
Showing 9 changed files with 615 additions and 7 deletions.
21 changes: 14 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ jobs:
uses: actions/download-artifact@v3
with:
name: snaps

- name: Install dependencies
run: |
# Python script dependencies
sudo python -m pip install --upgrade pip
sudo pip install flake8 pep8-naming boto3
- name: Lint check
run: |
flake8 . --count --show-source --statistics
- name: Install and setup
run: |
set -eux
Expand Down Expand Up @@ -160,13 +171,9 @@ jobs:
- name: Exercise RGW
run: |
set -eux
sudo microceph.radosgw-admin user create --uid=test --display-name=test
sudo microceph.radosgw-admin key create --uid=test --key-type=s3 --access-key fooAccessKey --secret-key fooSecretKey
sudo apt-get -qq install s3cmd
echo hello-radosgw > ~/test.txt
s3cmd --host localhost --host-bucket="localhost/%(bucket)" --access_key=fooAccessKey --secret_key=fooSecretKey --no-ssl mb s3://testbucket
s3cmd --host localhost --host-bucket="localhost/%(bucket)" --access_key=fooAccessKey --secret_key=fooSecretKey --no-ssl put -P ~/test.txt s3://testbucket
curl -s http://localhost/testbucket/test.txt | grep -F hello-radosgw
sudo microceph s3 create testUser --json > keys.json
sudo python3 scripts/appS3.py http://localhost:80 keys.json --obj-num 2
sudo microceph s3 delete testUser
- name: Test Cluster Config
run: |
Expand Down
1 change: 1 addition & 0 deletions microceph/api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ var Endpoints = []rest.Endpoint{
rgwServiceCmd,
configsCmd,
restartServiceCmd,
s3Cmd,
}
79 changes: 79 additions & 0 deletions microceph/api/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package api

import (
"encoding/json"
"net/http"

"github.com/canonical/lxd/lxd/response"
"github.com/canonical/microceph/microceph/api/types"
"github.com/canonical/microceph/microceph/ceph"
"github.com/canonical/microcluster/rest"
"github.com/canonical/microcluster/state"
)

// /1.0/resources endpoint.
var s3Cmd = rest.Endpoint{
Path: "s3",
Get: rest.EndpointAction{Handler: cmdS3Get, ProxyTarget: true},
Put: rest.EndpointAction{Handler: cmdS3Put, ProxyTarget: true},
Delete: rest.EndpointAction{Handler: cmdS3Delete, ProxyTarget: true},
}

func cmdS3Get(s *state.State, r *http.Request) response.Response {
var err error
var req types.S3User

err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
return response.InternalError(err)
}

// If a user name is passed.
if len(req.Name) > 0 {
getOutput, err := ceph.GetS3User(req)
if err != nil {
return response.SmartError(err)
}
return response.SyncResponse(true, getOutput)
} else {
listOutput, err := ceph.ListS3Users()
if err != nil {
return response.SmartError(err)
}
return response.SyncResponse(true, listOutput)
}
}

func cmdS3Put(s *state.State, r *http.Request) response.Response {
var err error
var req types.S3User

err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
return response.InternalError(err)
}

output, err := ceph.CreateS3User(req)
if err != nil {
return response.SmartError(err)
}

return response.SyncResponse(true, output)
}

func cmdS3Delete(s *state.State, r *http.Request) response.Response {
var err error
var req types.S3User

err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
return response.InternalError(err)
}

err = ceph.DeleteS3User(req.Name)
if err != nil {
return response.SmartError(err)
}

return response.EmptySyncResponse
}
9 changes: 9 additions & 0 deletions microceph/api/types/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Package types provides shared types and structs.
package types

// holds the name, access and secretkey required for exposing an S3 user.
type S3User struct {
Name string `json:"name" yaml:"name"`
Key string `json:"key" yaml:"key"`
Secret string `json:"secret" yaml:"secret"`
}
78 changes: 78 additions & 0 deletions microceph/ceph/rgw_s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package ceph

import (
"encoding/json"
"fmt"

"github.com/canonical/microceph/microceph/api/types"
)

func CreateS3User(user types.S3User) (string, error) {
args := []string{
"user",
"create",
fmt.Sprintf("--uid=%s", user.Name),
fmt.Sprintf("--display-name=%s", user.Name),
}

if len(user.Key) > 0 {
args = append(args, fmt.Sprintf("--access-key=%s", user.Key))
}

if len(user.Secret) > 0 {
args = append(args, fmt.Sprintf("--secret=%s", user.Secret))
}

output, err := processExec.RunCommand("radosgw-admin", args...)
if err != nil {
return "", err
}

return output, nil
}

func GetS3User(user types.S3User) (string, error) {
args := []string{
"user",
"info",
fmt.Sprintf("--uid=%s", user.Name),
}

output, err := processExec.RunCommand("radosgw-admin", args...)
if err != nil {
return "", err
}

return output, nil
}

func ListS3Users() ([]string, error) {
args := []string{
"user",
"list",
}

output, err := processExec.RunCommand("radosgw-admin", args...)
if err != nil {
return []string{}, err
}

ret := []string{}
json.Unmarshal([]byte(output), &ret)
return ret, nil
}

func DeleteS3User(name string) error {
args := []string{
"user",
"rm",
fmt.Sprintf("--uid=%s", name),
}

_, err := processExec.RunCommand("radosgw-admin", args...)
if err != nil {
return err
}

return nil
}
69 changes: 69 additions & 0 deletions microceph/client/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Package client provides a full Go API client.
package client

import (
"context"
"time"

"github.com/canonical/lxd/shared/api"
"github.com/canonical/lxd/shared/logger"
"github.com/canonical/microceph/microceph/api/types"
"github.com/canonical/microcluster/client"
)

func GetS3User(ctx context.Context, c *client.Client, user *types.S3User) (string, error) {
queryCtx, cancel := context.WithTimeout(ctx, time.Second*60)
defer cancel()

ret := ""
err := c.Query(queryCtx, "GET", api.NewURL().Path("s3"), user, &ret)
if err != nil {
logger.Error(err.Error())
return ret, err
}

return ret, nil
}

func ListS3Users(ctx context.Context, c *client.Client) ([]string, error) {
queryCtx, cancel := context.WithTimeout(ctx, time.Second*60)
defer cancel()

ret := []string{} // List of usernames
// GET request with no user name fetches all users.
err := c.Query(queryCtx, "GET", api.NewURL().Path("s3"), &types.S3User{Name: ""}, &ret)
if err != nil {
logger.Error(err.Error())
return ret, err
}

return ret, nil
}

func CreateS3User(ctx context.Context, c *client.Client, user *types.S3User) (string, error) {
queryCtx, cancel := context.WithTimeout(ctx, time.Second*60)
defer cancel()

ret := ""
err := c.Query(queryCtx, "PUT", api.NewURL().Path("s3"), user, &ret)
if err != nil {
logger.Error(err.Error())
return ret, err
}

return ret, nil
}

func DeleteS3User(ctx context.Context, c *client.Client, user *types.S3User) error {
queryCtx, cancel := context.WithTimeout(ctx, time.Second*60)
defer cancel()

ret := types.S3User{}
err := c.Query(queryCtx, "DELETE", api.NewURL().Path("s3"), user, &ret)
if err != nil {
logger.Error(err.Error())
return err
}

return nil
}
3 changes: 3 additions & 0 deletions microceph/cmd/microceph/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ func main() {
var cmdDisk = cmdDisk{common: &commonCmd}
app.AddCommand(cmdDisk.Command())

var cmdS3 = cmdS3{common: &commonCmd}
app.AddCommand(cmdS3.Command())

app.InitDefaultHelpCmd()

err := app.Execute()
Expand Down
Loading

0 comments on commit 6633df4

Please sign in to comment.