Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refactor to single instance garm client with auto init and login #48

Merged
merged 4 commits into from
Jan 8, 2024

Conversation

rafalgalaw
Copy link
Collaborator

Creates the garm-api client once as a single instance, so there are no more unnecesary login api calls on every reconcile. Also the operator initializes garm-server automatically again and attempts a login, once the garm-server dies or the auth token expires.

Essentially in main the client gets created once

main.go

if err = client.CreateInstance(client.GarmScopeParams{
	BaseURL:  config.Config.Garm.Server,
	Username: config.Config.Garm.Username,
	Password: config.Config.Garm.Password,
	Email:    config.Config.Garm.Email,
}); err != nil {
	return fmt.Errorf("unable to setup garm: %w", err)
}

Every garm-client method gets passed as callback to EnsureAuth

enterprise.go

func (s *enterpriseClient) ListEnterprises(param *enterprises.ListEnterprisesParams) (*enterprises.ListEnterprisesOK, error) {
	return EnsureAuth(func() (*enterprises.ListEnterprisesOK, error) {
		metrics.TotalGarmCalls.WithLabelValues("enterprises.List").Inc()
		enterprises, err := s.Client().Enterprises.ListEnterprises(param, s.Token())
		if err != nil {
			metrics.GarmCallErrors.WithLabelValues("enterprises.List").Inc()
			return nil, err
		}
		return enterprises, nil
	})
}

Inside EnsureAuth, the client method gets executed, and checked for a 401 http error, which would result in an intit and login call, before retrying the same client method again. The single instance client is then authenticated again for every caller.

client.go

func EnsureAuth[T interface{}](f Func[T]) (T, error) {
	result, err := f()
	if err != nil && IsUnauthenticatedError(err) {
		metrics.GarmCallErrors.WithLabelValues("client.Unauthenticated").Inc()

		err = Instance.Init()
		if err != nil {
			return result, err
		}

		err = Instance.Login()
		if err != nil {
			return result, err
		}

		result, err = f()
	}
	return result, err
}

@rafalgalaw rafalgalaw changed the title Feat/single instance client refactor to single instance garm client with auto init and login Dec 28, 2023
@rafalgalaw rafalgalaw linked an issue Dec 28, 2023 that may be closed by this pull request
@rafalgalaw rafalgalaw changed the title refactor to single instance garm client with auto init and login feat: refactor to single instance garm client with auto init and login Dec 28, 2023
@rafalgalaw rafalgalaw marked this pull request as ready for review January 8, 2024 07:18
Copy link
Member

@bavarianbidi bavarianbidi left a comment

Choose a reason for hiding this comment

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

nice refactoring, really like it ❤️
just one nit about variable naming

@@ -20,6 +20,8 @@ import (
"github.com/mercedes-benz/garm-operator/pkg/metrics"
)

var Instance BaseClient
Copy link
Member

Choose a reason for hiding this comment

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

I'm bothered by the term Instance here ... Instance in the scope of GARM could be a Runner as well.

What do you think about one of the following two options:

  • Instance will be renamed to GarmClient
  • As BaseClient is an extended version of garmClient.GarmAPI, BaseClient will become GarmClient and with that Instance will be BaseClient (or just Client)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes you are right, this might be confusing. I´ll probably like the second option better: then its clear that a GarmClient is the defact Base which has all necessary methods for Auth and default API methods for all garm resources. And the Instance of it is an instanciated Client.

Copy link
Member

@bavarianbidi bavarianbidi left a comment

Choose a reason for hiding this comment

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

LGTM

just one idea came into my mind (could be a dedicated follow up PR)
expose the expiration-time of the current used token as metric.

@rafalgalaw rafalgalaw merged commit 2ad8412 into main Jan 8, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Automatic Auth Token Refresh & GARM Init
2 participants