Skip to content

Commit

Permalink
Merge pull request #297 from sapcc/new-go-bits
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperSandro2000 authored Nov 12, 2024
2 parents 651f907 + 4e39d2c commit 823ffb9
Show file tree
Hide file tree
Showing 47 changed files with 205 additions and 24,248 deletions.
6 changes: 1 addition & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ require (
github.com/dlmiddlecote/sqlstats v1.0.2
github.com/go-gorp/gorp/v3 v3.1.0
github.com/gophercloud/gophercloud/v2 v2.2.0
github.com/gophercloud/utils/v2 v2.0.0-20241107125844-da754bc75cd6
github.com/gorilla/mux v1.8.1
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/common v0.60.1
github.com/rs/cors v1.11.1
github.com/sapcc/go-api-declarations v1.12.9
github.com/sapcc/go-bits v0.0.0-20241107000306-6eb1626e14d0
github.com/sapcc/go-bits v0.0.0-20241112121120-a312b675efd7
go.uber.org/automaxprocs v1.6.0
gopkg.in/yaml.v2 v2.4.0
)
Expand All @@ -29,7 +28,6 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand All @@ -39,7 +37,5 @@ require (
github.com/sergi/go-diff v1.3.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gophercloud/gophercloud/v2 v2.2.0 h1:STqqnSXuhcg1OPBOZ14z6JDm8fKIN13H2bJg6bBuHp8=
github.com/gophercloud/gophercloud/v2 v2.2.0/go.mod h1:f2hMRC7Kakbv5vM7wSGHrIPZh6JZR60GVHryJlF/K44=
github.com/gophercloud/utils/v2 v2.0.0-20241107125844-da754bc75cd6 h1:Vikb1i71pW5yb/ayp+Cw6Z3Wc+3NtT+ui/t4LyJl7dY=
github.com/gophercloud/utils/v2 v2.0.0-20241107125844-da754bc75cd6/go.mod h1:9KHhEdDkA/4hTdwxS0sALJIp2hFSjrODlKMQcFU2GFw=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -98,8 +96,6 @@ github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
Expand Down Expand Up @@ -159,8 +155,8 @@ github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sapcc/go-api-declarations v1.12.9 h1:4CWkt333oQxGnbka1TH4qApC0bxZe+WIBduygEcxiNw=
github.com/sapcc/go-api-declarations v1.12.9/go.mod h1:83R3hTANhuRXt/pXDby37IJetw8l7DG41s33Tp9NXxI=
github.com/sapcc/go-bits v0.0.0-20241107000306-6eb1626e14d0 h1:4dDWf8AxpL1FGLrAAsTSSX0K7wB9Zkti2WxTj6xvGzQ=
github.com/sapcc/go-bits v0.0.0-20241107000306-6eb1626e14d0/go.mod h1:edzu9ZBNooNFNX1J70nkhV2cOibYvADvr4C39K0stbc=
github.com/sapcc/go-bits v0.0.0-20241112121120-a312b675efd7 h1:jp2NiKpUY5Jzlfw1oFqg/EkMtq72OgQGV3KCIVDGlH0=
github.com/sapcc/go-bits v0.0.0-20241112121120-a312b675efd7/go.mod h1:P4F8aMHla5I0gRW+eOEYrhM89h3heEg0nypTZZcKoBQ=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
Expand Down
37 changes: 19 additions & 18 deletions internal/core/openstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/projects"
"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles"
"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens"
"github.com/sapcc/go-bits/gophercloudext"
)

// ProviderClient is an interface for an internal type that wraps
Expand Down Expand Up @@ -59,7 +60,6 @@ type ProviderClient interface {
// providerClientImpl is the implementation for the ProviderClient interface.
type providerClientImpl struct {
pc *gophercloud.ProviderClient
ao gophercloud.AuthOptions
eo gophercloud.EndpointOpts
roleIDForName map[string]string
projectCache map[string]*CachedProject // key = UUID, nil value = project does not exist
Expand Down Expand Up @@ -90,8 +90,8 @@ type CachedDomain struct {
}

// NewProviderClient constructs a new ProviderClient instance.
func NewProviderClient(ctx context.Context, ao gophercloud.AuthOptions, eo gophercloud.EndpointOpts) (ProviderClient, error) {
pc, err := openstack.AuthenticatedClient(ctx, ao)
func NewProviderClient(ctx context.Context) (ProviderClient, error) {
pc, eo, err := gophercloudext.NewProviderClient(ctx, nil)
if err != nil {
return nil, err
}
Expand All @@ -116,7 +116,6 @@ func NewProviderClient(ctx context.Context, ao gophercloud.AuthOptions, eo gophe

return &providerClientImpl{
pc: pc,
ao: ao,
eo: eo,
roleIDForName: roleIDForName,
projectCache: make(map[string]*CachedProject),
Expand All @@ -137,17 +136,19 @@ func (p *providerClientImpl) ProjectScopedClient(ctx context.Context, scope Proj

func (p *providerClientImpl) projectScopedClientImpl(ctx context.Context, scope ProjectScope, firstPass bool) (*gophercloud.ProviderClient, gophercloud.EndpointOpts, error) {
// auth into the target project
ao := p.ao
ao.Scope = &gophercloud.AuthScope{ProjectID: scope.ID}
pc, err := openstack.AuthenticatedClient(ctx, ao)
pc, eo, err := gophercloudext.NewProviderClient(ctx, &gophercloudext.ClientOpts{
CustomizeAuthOptions: func(ao *gophercloud.AuthOptions) {
ao.Scope = &gophercloud.AuthScope{ProjectID: scope.ID}
},
})
if err != nil {
//NOTE: If we don't have any roles assigned in the project yet, we will get
// a 401, even if the provided credentials are correct. This is not a fatal
// error, we just need to carry on and assign roles.
if gophercloud.ResponseCodeIs(err, http.StatusUnauthorized) {
pc = nil
} else {
return nil, p.eo, fmt.Errorf("cannot authenticate into project %s: %w", scope.ID, err)
return nil, eo, fmt.Errorf("cannot authenticate into project %s: %w", scope.ID, err)
}
}

Expand All @@ -164,20 +165,20 @@ func (p *providerClientImpl) projectScopedClientImpl(ctx context.Context, scope
// our cloud-admin-scope AuthResult for that
result, ok = p.pc.GetAuthResult().(tokens.CreateResult)
if !ok {
return nil, p.eo, fmt.Errorf("unknown type for AuthResult: %T", p.pc.GetAuthResult())
return nil, eo, fmt.Errorf("unknown type for AuthResult: %T", p.pc.GetAuthResult())
}
} else {
if len(scope.RoleNames) == 0 {
// no checks to perform
return pc, p.eo, nil
return pc, eo, nil
}
result, ok = pc.GetAuthResult().(tokens.CreateResult)
if !ok {
return nil, p.eo, fmt.Errorf("unknown type for AuthResult: %T", p.pc.GetAuthResult())
return nil, eo, fmt.Errorf("unknown type for AuthResult: %T", p.pc.GetAuthResult())
}
assignedRoles, err = result.ExtractRoles()
if err != nil {
return nil, p.eo, fmt.Errorf("cannot get role assignments for project scope: %w", err)
return nil, eo, fmt.Errorf("cannot get role assignments for project scope: %w", err)
}
}

Expand All @@ -191,35 +192,35 @@ func (p *providerClientImpl) projectScopedClientImpl(ctx context.Context, scope
}
if len(isRequestedRole) == 0 {
// all required roles are assigned
return pc, p.eo, nil
return pc, eo, nil
}

// not all roles present -> try at most once to assign missing roles
// (this check prevents an infinite loop in case of unforeseen problems)
if !firstPass {
return nil, p.eo, fmt.Errorf("some roles in project %s are still missing despite successful assignment: %v",
return nil, eo, fmt.Errorf("some roles in project %s are still missing despite successful assignment: %v",
scope.ID, isRequestedRole)
}
user, err := result.ExtractUser()
if err != nil {
return nil, p.eo, fmt.Errorf("cannot get own user ID: %w", err)
return nil, eo, fmt.Errorf("cannot get own user ID: %w", err)
}
identityV3, err := p.CloudAdminClient(openstack.NewIdentityV3)
if err != nil {
return nil, p.eo, err
return nil, eo, err
}
for roleName := range isRequestedRole {
roleID := p.roleIDForName[roleName]
if roleID == "" {
return nil, p.eo, fmt.Errorf("no such role: %s", roleName)
return nil, eo, fmt.Errorf("no such role: %s", roleName)
}
opts := roles.AssignOpts{
UserID: user.ID,
ProjectID: scope.ID,
}
err := roles.Assign(ctx, identityV3, roleID, opts).ExtractErr()
if err != nil {
return nil, p.eo, fmt.Errorf("could not assign role %s in project %s: %w", roleName, scope.ID, err)
return nil, eo, fmt.Errorf("could not assign role %s in project %s: %w", roleName, scope.ID, err)
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/plugins/nfs-shares.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (m *assetManagerNFS) GetAssetStatus(ctx context.Context, res db.Resource, a
if err != nil {
return core.AssetStatus{}, fmt.Errorf("cannot get status of share %s from Manila API: %w", assetUUID, err)
}
if share.Size < 0 || uint64(share.Size) != status.Size { //nolint:gosec // we cannot store exabytes and negative check is done
if share.Size < 0 || uint64(share.Size) != status.Size {
return core.AssetStatus{}, fmt.Errorf(
"inconsistent size reports for share %s: Prometheus says %d GiB, Manila says %d GiB",
assetUUID, status.Size, share.Size)
Expand Down
21 changes: 3 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ import (

"github.com/dlmiddlecote/sqlstats"
"github.com/go-gorp/gorp/v3"
"github.com/gophercloud/gophercloud/v2"
"github.com/gophercloud/gophercloud/v2/openstack"
"github.com/gophercloud/utils/v2/openstack/clientconfig"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/cors"
Expand Down Expand Up @@ -98,22 +96,9 @@ func main() {
dbi := must.Return(db.Init(dbURL))
prometheus.MustRegister(sqlstats.NewStatsCollector("castellum", dbi.Db))

ctx := httpext.ContextWithSIGINT(context.Background(), 10*time.Second)

// initialize OpenStack connection
ao, err := clientconfig.AuthOptions(nil)
if err != nil {
logg.Fatal("cannot find OpenStack credentials: " + err.Error())
}
ao.AllowReauth = true
providerClient, err := core.NewProviderClient(ctx, *ao, gophercloud.EndpointOpts{
// note that empty values are acceptable in both fields
Region: os.Getenv("OS_REGION_NAME"),
Availability: gophercloud.Availability(os.Getenv("OS_INTERFACE")),
})
if err != nil {
logg.Fatal("cannot connect to OpenStack: " + err.Error())
}
ctx := httpext.ContextWithSIGINT(context.Background(), 10*time.Second)
providerClient := must.Return(core.NewProviderClient(ctx))

// get max asset sizes
cfg := must.Return(core.LoadConfig(configPath))
Expand Down Expand Up @@ -167,7 +152,7 @@ func runAPI(ctx context.Context, cfg core.Config, dbi *gorp.DbMap, team core.Ass
IdentityV3: identityV3,
Cacher: gopherpolicy.InMemoryCacher(),
}
must.Succeed(tv.LoadPolicyFile(osext.MustGetenv("CASTELLUM_OSLO_POLICY_PATH")))
must.Succeed(tv.LoadPolicyFile(osext.MustGetenv("CASTELLUM_OSLO_POLICY_PATH"), nil))

// wrap the main API handler in several layers of middleware
corsMiddleware := cors.New(cors.Options{
Expand Down
Loading

0 comments on commit 823ffb9

Please sign in to comment.