Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/context/store/metadatastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
const (
metadataDir = "meta"
metaFile = "meta.json"
lockFile = "lock"
)

type metadataStore struct {
Expand Down
107 changes: 97 additions & 10 deletions cli/context/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import (
"encoding/json"
"io"
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"strings"

"github.com/docker/docker/errdefs"
"github.com/gofrs/flock"
"github.com/hashicorp/go-multierror"
Copy link
Member

@thaJeztah thaJeztah Dec 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Go's native multi-errors for this? (errors.Join() (https://pkg.go.dev/errors#Join)), or would we loose too much functionality?

I think the general trend is to (try) moving away from hashicorp's packages as licensing for some of them becomes more risky (plus trying to use stdlib where possible in general)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can switch to errors.Join if you don't mind requiring Go 1.20. The vendor.mod requires Go 1.19 at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a few patches to switch to the Go 1.20 errors package to see how it looks.

"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -98,6 +101,7 @@ type ContextTLSData struct {
// If the directory does not exist or is empty, initialize it
func New(dir string, cfg Config) *ContextStore {
metaRoot := filepath.Join(dir, metadataDir)
lockPath := filepath.Join(dir, lockFile)
tlsRoot := filepath.Join(dir, tlsDir)

return &ContextStore{
Expand All @@ -108,17 +112,44 @@ func New(dir string, cfg Config) *ContextStore {
tls: &tlsStore{
root: tlsRoot,
},
lockFile: flock.New(lockPath),
}
}

// ContextStore implements Store.
type ContextStore struct {
meta *metadataStore
tls *tlsStore
meta *metadataStore
tls *tlsStore
lockFile *flock.Flock
}

func (s *ContextStore) lock() error {
if err := os.MkdirAll(filepath.Dir(s.lockFile.Path()), 0o755); err != nil {
return errors.Wrapf(err, "creating context store lock directory")
}
if err := s.lockFile.Lock(); err != nil {
return errors.Wrapf(err, "locking context store lock")
}
return nil
}

func (s *ContextStore) unlock() error {
if err := s.lockFile.Unlock(); err != nil {
return errors.Wrapf(err, "unlocking context store lock")
}
return nil
}

// List return all contexts.
func (s *ContextStore) List() ([]Metadata, error) {
func (s *ContextStore) List() (_ []Metadata, errs error) {
if err := s.lock(); err != nil {
return nil, err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
return s.meta.list()
}

Expand All @@ -136,12 +167,28 @@ func Names(s Lister) ([]string, error) {
}

// CreateOrUpdate creates or updates metadata for the context.
func (s *ContextStore) CreateOrUpdate(meta Metadata) error {
func (s *ContextStore) CreateOrUpdate(meta Metadata) (errs error) {
if err := s.lock(); err != nil {
return err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
return s.meta.createOrUpdate(meta)
}

// Remove deletes the context with the given name, if found.
func (s *ContextStore) Remove(name string) error {
func (s *ContextStore) Remove(name string) (errs error) {
if err := s.lock(); err != nil {
return err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
if err := s.meta.remove(name); err != nil {
return errors.Wrapf(err, "failed to remove context %s", name)
}
Expand All @@ -153,13 +200,29 @@ func (s *ContextStore) Remove(name string) error {

// GetMetadata returns the metadata for the context with the given name.
// It returns an errdefs.ErrNotFound if the context was not found.
func (s *ContextStore) GetMetadata(name string) (Metadata, error) {
func (s *ContextStore) GetMetadata(name string) (_ Metadata, errs error) {
if err := s.lock(); err != nil {
return Metadata{}, err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
return s.meta.get(name)
}

// ResetTLSMaterial removes TLS data for all endpoints in the context and replaces
// it with the new data.
func (s *ContextStore) ResetTLSMaterial(name string, data *ContextTLSData) error {
func (s *ContextStore) ResetTLSMaterial(name string, data *ContextTLSData) (errs error) {
if err := s.lock(); err != nil {
return err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
if err := s.tls.remove(name); err != nil {
return err
}
Expand All @@ -178,7 +241,15 @@ func (s *ContextStore) ResetTLSMaterial(name string, data *ContextTLSData) error

// ResetEndpointTLSMaterial removes TLS data for the given context and endpoint,
// and replaces it with the new data.
func (s *ContextStore) ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error {
func (s *ContextStore) ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) (errs error) {
if err := s.lock(); err != nil {
return err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
if err := s.tls.removeEndpoint(contextName, endpointName); err != nil {
return err
}
Expand All @@ -195,13 +266,29 @@ func (s *ContextStore) ResetEndpointTLSMaterial(contextName string, endpointName

// ListTLSFiles returns the list of TLS files present for each endpoint in the
// context.
func (s *ContextStore) ListTLSFiles(name string) (map[string]EndpointFiles, error) {
func (s *ContextStore) ListTLSFiles(name string) (_ map[string]EndpointFiles, errs error) {
if err := s.lock(); err != nil {
return nil, err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
return s.tls.listContextData(name)
}

// GetTLSData reads, and returns the content of the given fileName for an endpoint.
// It returns an errdefs.ErrNotFound if the file was not found.
func (s *ContextStore) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
func (s *ContextStore) GetTLSData(contextName, endpointName, fileName string) (_ []byte, errs error) {
if err := s.lock(); err != nil {
return nil, err
}
defer func() {
if err := s.unlock(); err != nil {
errs = multierror.Append(errs, err)
}
}()
return s.tls.getData(contextName, endpointName, fileName)
}

Expand Down
9 changes: 9 additions & 0 deletions cli/context/store/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ import (
is "gotest.tools/v3/assert/cmp"
)

func TestNew(t *testing.T) {
s := New(path.Join(t.TempDir(), "does", "not", "exist", "yet"), testCfg)
assert.Assert(t, s != nil)
// Check that the file lock works even when the directory does not exist yet.
all, err := s.List()
assert.NilError(t, err)
assert.Assert(t, len(all) == 0)
}

type endpoint struct {
Foo string `json:"a_very_recognizable_field_name"`
}
Expand Down
3 changes: 3 additions & 0 deletions vendor.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ require (
github.com/docker/go-connections v0.4.1-0.20231110212414-fa09c952e3ea
github.com/docker/go-units v0.5.0
github.com/fvbommel/sortorder v1.0.2
github.com/gofrs/flock v0.8.1
github.com/gogo/protobuf v1.3.2
github.com/google/go-cmp v0.5.9
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/hashicorp/go-multierror v1.1.1
github.com/mattn/go-runewidth v0.0.14
github.com/mitchellh/mapstructure v1.3.2
github.com/moby/patternmatcher v0.6.0
Expand Down Expand Up @@ -61,6 +63,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
Expand Down
7 changes: 7 additions & 0 deletions vendor.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
Expand Down Expand Up @@ -122,6 +124,11 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand Down
24 changes: 24 additions & 0 deletions vendor/github.com/gofrs/flock/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions vendor/github.com/gofrs/flock/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions vendor/github.com/gofrs/flock/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions vendor/github.com/gofrs/flock/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions vendor/github.com/gofrs/flock/appveyor.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading