Skip to content

Commit

Permalink
feat(api,cli): add CRUD v2 organization and region (#6296)
Browse files Browse the repository at this point in the history
  • Loading branch information
sguiheux authored Sep 22, 2022
1 parent d8b83bd commit b309ce9
Show file tree
Hide file tree
Showing 22 changed files with 1,011 additions and 13 deletions.
4 changes: 3 additions & 1 deletion cli/cdsctl/experimental.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ var experimentalCmd = cli.Command{

func experimentalCommands() []*cobra.Command {
return []*cobra.Command{
experimentalRbac(),
experimentalOrganization(),
experimentalRegion(),
experimentalProject(),
experimentalRbac(),
experimentalWorkerModel(),
}
}
Expand Down
99 changes: 99 additions & 0 deletions cli/cdsctl/experimental_organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"context"
"github.com/ovh/cds/sdk"
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
)

var experimentalOrganizationCmd = cli.Command{
Name: "organization",
Aliases: []string{"org", "orga"},
Short: "CDS Experimental organization commands",
}

func experimentalOrganization() *cobra.Command {
return cli.NewCommand(experimentalOrganizationCmd, nil, []*cobra.Command{
cli.NewCommand(organizationAddCmd, organizationAddFunc, nil, withAllCommandModifiers()...),
cli.NewGetCommand(organizationGetCmd, organizationGetFunc, nil, withAllCommandModifiers()...),
cli.NewListCommand(organizationListCmd, organizationListFunc, nil, withAllCommandModifiers()...),
cli.NewDeleteCommand(organizationDeleteCmd, organizationDeleteFunc, nil, withAllCommandModifiers()...),
})
}

var organizationAddCmd = cli.Command{
Name: "add",
Aliases: []string{"create"},
Short: "Create a new organization",
Example: "cdsctl organization add <organization_name>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "organizationIdentifier"},
},
}

func organizationAddFunc(v cli.Values) error {
orga := sdk.Organization{Name: v.GetString("organizationIdentifier")}
if err := client.OrganizationAdd(context.Background(), orga); err != nil {
return err
}
return nil
}

var organizationGetCmd = cli.Command{
Name: "show",
Aliases: []string{"get"},
Short: "Get an organization by its identifier",
Example: "cdsctl organization show <organization_identifier>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "organizationIdentifier"},
},
}

func organizationGetFunc(v cli.Values) (interface{}, error) {
orga, err := client.OrganizationGet(context.Background(), v.GetString("organizationIdentifier"))
if err != nil {
return orga, err
}
return orga, nil
}

var organizationListCmd = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Short: "List all organizations",
Example: "cdsctl organization list",
Ctx: []cli.Arg{},
}

func organizationListFunc(_ cli.Values) (cli.ListResult, error) {
orgas, err := client.OrganizationList(context.Background())
if err != nil {
return nil, err
}
return cli.AsListResult(orgas), nil
}

var organizationDeleteCmd = cli.Command{
Name: "delete",
Aliases: []string{"remove", "rm"},
Short: "Remove organization",
Example: "cdsctl organization delete",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{
Name: "organizationIdentifier",
},
},
}

func organizationDeleteFunc(v cli.Values) error {
err := client.OrganizationDelete(context.Background(), v.GetString("organizationIdentifier"))
if v.GetBool("force") && sdk.ErrorIs(err, sdk.ErrNotFound) {
return nil
}
return err
}
99 changes: 99 additions & 0 deletions cli/cdsctl/experimental_region.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"context"
"github.com/ovh/cds/sdk"
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
)

var experimentalRegionCmd = cli.Command{
Name: "region",
Aliases: []string{"org", "orga"},
Short: "CDS Experimental region commands",
}

func experimentalRegion() *cobra.Command {
return cli.NewCommand(experimentalRegionCmd, nil, []*cobra.Command{
cli.NewCommand(regionAddCmd, regionAddFunc, nil, withAllCommandModifiers()...),
cli.NewGetCommand(regionGetCmd, regionGetFunc, nil, withAllCommandModifiers()...),
cli.NewListCommand(regionListCmd, regionListFunc, nil, withAllCommandModifiers()...),
cli.NewDeleteCommand(regionDeleteCmd, regionDeleteFunc, nil, withAllCommandModifiers()...),
})
}

var regionAddCmd = cli.Command{
Name: "add",
Aliases: []string{"create"},
Short: "Create a new region",
Example: "cdsctl region add <region_name>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "regionIdentifier"},
},
}

func regionAddFunc(v cli.Values) error {
reg := sdk.Region{Name: v.GetString("regionIdentifier")}
if err := client.RegionAdd(context.Background(), reg); err != nil {
return err
}
return nil
}

var regionGetCmd = cli.Command{
Name: "show",
Aliases: []string{"get"},
Short: "Get an region by its identifier",
Example: "cdsctl region show <region_identifier>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "regionIdentifier"},
},
}

func regionGetFunc(v cli.Values) (interface{}, error) {
reg, err := client.RegionGet(context.Background(), v.GetString("regionIdentifier"))
if err != nil {
return reg, err
}
return reg, nil
}

var regionListCmd = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Short: "List all regions",
Example: "cdsctl region list",
Ctx: []cli.Arg{},
}

func regionListFunc(_ cli.Values) (cli.ListResult, error) {
regions, err := client.RegionList(context.Background())
if err != nil {
return nil, err
}
return cli.AsListResult(regions), nil
}

var regionDeleteCmd = cli.Command{
Name: "delete",
Aliases: []string{"remove", "rm"},
Short: "Remove region",
Example: "cdsctl region delete",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{
Name: "regionIdentifier",
},
},
}

func regionDeleteFunc(v cli.Values) error {
err := client.RegionDelete(context.Background(), v.GetString("regionIdentifier"))
if v.GetBool("force") && sdk.ErrorIs(err, sdk.ErrNotFound) {
return nil
}
return err
}
4 changes: 4 additions & 0 deletions engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,12 @@ func (api *API) InitRouter() {

r.Handle("/v2/organization", nil, r.POSTv2(api.postOrganizationHandler), r.GETv2(api.getOrganizationsHandler))
r.Handle("/v2/organization/{organizationIdentifier}", nil, r.GETv2(api.getOrganizationHandler), r.DELETEv2(api.deleteOrganizationHandler))

r.Handle("/v2/rbac/import", nil, r.POSTv2(api.postImportRbacHandler))

r.Handle("/v2/region", nil, r.POSTv2(api.postRegionHandler), r.GETv2(api.getRegionsHandler))
r.Handle("/v2/region/{regionIdentifier}", nil, r.GETv2(api.getRegionHandler), r.DELETEv2(api.deleteRegionHandler))

r.Handle("/v2/repository/analyze", Scope(sdk.AuthConsumerScopeHooks), r.POSTv2(api.postRepositoryAnalysisHandler))
r.Handle("/v2/project/repositories", Scope(sdk.AuthConsumerScopeHooks), r.GETv2(api.getAllRepositoriesHandler))
r.Handle("/v2/project/repositories/{repositoryIdentifier}/hook", Scope(sdk.AuthConsumerScopeHooks), r.GETv2(api.getRepositoryHookHandler))
Expand Down
6 changes: 5 additions & 1 deletion engine/api/rbac/rule_global.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ func hasGlobalRole(ctx context.Context, auth *sdk.AuthConsumer, _ cache.Store, d

// PermissionManage return nil if the current AuthConsumer have the ProjectRoleManage on current project KEY
func PermissionManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.RoleManagePermission)
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManagePermission)
}

func OrganizationManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManageOrganization)
}

func RegionManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManageRegion)
}
84 changes: 84 additions & 0 deletions engine/api/region/dao_region.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package region

import (
"context"

"github.com/go-gorp/gorp"
"github.com/rockbears/log"

"github.com/ovh/cds/engine/api/database/gorpmapping"
"github.com/ovh/cds/engine/gorpmapper"
"github.com/ovh/cds/sdk"
)

func Insert(ctx context.Context, db gorpmapper.SqlExecutorWithTx, region *sdk.Region) error {
region.ID = sdk.UUID()
dbData := &dbRegion{Region: *region}
if err := gorpmapping.InsertAndSign(ctx, db, dbData); err != nil {
return err
}
*region = dbData.Region
return nil
}

func Delete(db gorpmapper.SqlExecutorWithTx, regionID string) error {
_, err := db.Exec("DELETE FROM region WHERE id = $1", regionID)
return sdk.WrapError(err, "cannot delete region %s", regionID)
}

func getRegion(ctx context.Context, db gorp.SqlExecutor, query gorpmapping.Query) (*sdk.Region, error) {
var dbRegion dbRegion
found, err := gorpmapping.Get(ctx, db, query, &dbRegion)
if err != nil {
return nil, err
}
if !found {
return nil, sdk.WithStack(sdk.ErrNotFound)
}

isValid, err := gorpmapping.CheckSignature(dbRegion, dbRegion.Signature)
if err != nil {
return nil, err
}
if !isValid {
log.Error(ctx, "region %s / %s data corrupted", dbRegion.ID, dbRegion.Name)
return nil, sdk.WithStack(sdk.ErrNotFound)
}
return &dbRegion.Region, nil
}

func getAllRegions(ctx context.Context, db gorp.SqlExecutor, query gorpmapping.Query) ([]sdk.Region, error) {
var res []dbRegion
if err := gorpmapping.GetAll(ctx, db, query, &res); err != nil {
return nil, err
}

regions := make([]sdk.Region, 0, len(res))
for _, r := range res {
isValid, err := gorpmapping.CheckSignature(r, r.Signature)
if err != nil {
return nil, err
}
if !isValid {
log.Error(ctx, "region %d / %s data corrupted", r.ID, r.Name)
continue
}
regions = append(regions, r.Region)
}
return regions, nil
}

func LoadAllRegions(ctx context.Context, db gorp.SqlExecutor) ([]sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region`)
return getAllRegions(ctx, db, query)
}

func LoadRegionByName(ctx context.Context, db gorp.SqlExecutor, name string) (*sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region WHERE region.name = $1`).Args(name)
return getRegion(ctx, db, query)
}

func LoadRegionByID(ctx context.Context, db gorp.SqlExecutor, ID string) (*sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region WHERE region.id = $1`).Args(ID)
return getRegion(ctx, db, query)
}
23 changes: 23 additions & 0 deletions engine/api/region/gorp_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package region

import (
"github.com/ovh/cds/engine/api/database/gorpmapping"
"github.com/ovh/cds/engine/gorpmapper"
"github.com/ovh/cds/sdk"
)

func init() {
gorpmapping.Register(gorpmapping.New(dbRegion{}, "region", false, "id"))
}

type dbRegion struct {
sdk.Region
gorpmapper.SignedEntity
}

func (o dbRegion) Canonical() gorpmapper.CanonicalForms {
_ = []interface{}{o.ID, o.Name}
return []gorpmapper.CanonicalForm{
"{{.ID}}{{.Name}}",
}
}
Loading

0 comments on commit b309ce9

Please sign in to comment.