Use authentication token from config for communication with Nomad

This commit is contained in:
Jan-Eric Hellenberg
2021-07-26 11:41:30 +02:00
committed by Jan-Eric Hellenberg
parent 23b726cef9
commit 3aa1227db6
7 changed files with 58 additions and 46 deletions

View File

@ -51,7 +51,7 @@ golangci-lint: ## Lint the source code using golangci-lint
lint: golangci-lint ## Lint the source code using all linters lint: golangci-lint ## Lint the source code using all linters
.PHONY: mock .PHONY: mock
snaked_name=$(shell sed -e "s/\([A-Z]\)/_\L\1/g" -e "s/^_//" <<< "$(name)") snaked_name=$(shell sed -e "s/\([a-z]\)\([A-Z]\)/\1_\2/g" -e "s/\([A-Z]\)/\L\1/g" -e "s/^_//" <<< "$(name)")
mock: deps ## Create/Update a mock. Example: make mock name=apiQuerier pkg=./nomad mock: deps ## Create/Update a mock. Example: make mock name=apiQuerier pkg=./nomad
@mockery \ @mockery \
--name=$(name) \ --name=$(name) \

View File

@ -45,7 +45,11 @@ func runServer(server *http.Server) {
func initServer() *http.Server { func initServer() *http.Server {
// API initialization // API initialization
nomadAPIClient, err := nomad.NewExecutorAPI(config.Config.NomadAPIURL(), config.Config.Nomad.Namespace) nomadAPIClient, err := nomad.NewExecutorAPI(
config.Config.NomadAPIURL(),
config.Config.Nomad.Namespace,
config.Config.Nomad.Token,
)
if err != nil { if err != nil {
log.WithError(err).WithField("nomad url", config.Config.NomadAPIURL()).Fatal("Error parsing the nomad url") log.WithError(err).WithField("nomad url", config.Config.NomadAPIURL()).Fatal("Error parsing the nomad url")
} }

View File

@ -16,7 +16,7 @@ var (
// apiQuerier provides access to the Nomad functionality. // apiQuerier provides access to the Nomad functionality.
type apiQuerier interface { type apiQuerier interface {
// init prepares an apiClient to be able to communicate to a provided Nomad API. // init prepares an apiClient to be able to communicate to a provided Nomad API.
init(nomadURL *url.URL, nomadNamespace string) (err error) init(nomadURL *url.URL, nomadNamespace, nomadToken string) (err error)
// LoadJobList loads the list of jobs from the Nomad API. // LoadJobList loads the list of jobs from the Nomad API.
LoadJobList() (list []*nomadApi.JobListStub, err error) LoadJobList() (list []*nomadApi.JobListStub, err error)
@ -61,11 +61,12 @@ type nomadAPIClient struct {
namespace string namespace string
} }
func (nc *nomadAPIClient) init(nomadURL *url.URL, nomadNamespace string) (err error) { func (nc *nomadAPIClient) init(nomadURL *url.URL, nomadNamespace, nomadToken string) (err error) {
nc.client, err = nomadApi.NewClient(&nomadApi.Config{ nc.client, err = nomadApi.NewClient(&nomadApi.Config{
Address: nomadURL.String(), Address: nomadURL.String(),
TLSConfig: &nomadApi.TLSConfig{}, TLSConfig: &nomadApi.TLSConfig{},
Namespace: nomadNamespace, Namespace: nomadNamespace,
SecretID: nomadToken,
}) })
if err != nil { if err != nil {
return fmt.Errorf("error creating new Nomad client: %w", err) return fmt.Errorf("error creating new Nomad client: %w", err)
@ -146,7 +147,13 @@ func (nc *nomadAPIClient) AllocationStream(ctx context.Context) (<-chan *nomadAp
stream, err := nc.client.EventStream().Stream( stream, err := nc.client.EventStream().Stream(
ctx, ctx,
map[nomadApi.Topic][]string{ map[nomadApi.Topic][]string{
nomadApi.TopicAllocation: {}, nomadApi.TopicAllocation: {
// Necessary to have the "topic" URL param show up in the HTTP request to Nomad.
// Without the param, Nomad will try to deliver all event types.
// However, this includes some events that require a management authentication token.
// As Poseidon uses no such token, the request will return a permission denied error.
"*",
},
}, },
0, 0,
nc.queryOptions()) nc.queryOptions())

View File

@ -42,13 +42,13 @@ func (_m *apiQuerierMock) AllocationStream(ctx context.Context) (<-chan *api.Eve
return r0, r1 return r0, r1
} }
// DeleteRunner provides a mock function with given fields: runnerId // DeleteRunner provides a mock function with given fields: runnerID
func (_m *apiQuerierMock) DeleteRunner(runnerId string) error { func (_m *apiQuerierMock) DeleteRunner(runnerID string) error {
ret := _m.Called(runnerId) ret := _m.Called(runnerID)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok { if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(runnerId) r0 = rf(runnerID)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@ -101,19 +101,19 @@ func (_m *apiQuerierMock) Execute(jobID string, ctx context.Context, command []s
} }
// JobScale provides a mock function with given fields: jobID // JobScale provides a mock function with given fields: jobID
func (_m *apiQuerierMock) JobScale(jobId string) (uint, error) { func (_m *apiQuerierMock) JobScale(jobID string) (uint, error) {
ret := _m.Called(jobId) ret := _m.Called(jobID)
var r0 uint var r0 uint
if rf, ok := ret.Get(0).(func(string) uint); ok { if rf, ok := ret.Get(0).(func(string) uint); ok {
r0 = rf(jobId) r0 = rf(jobID)
} else { } else {
r0 = ret.Get(0).(uint) r0 = ret.Get(0).(uint)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(jobId) r1 = rf(jobID)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@ -166,12 +166,12 @@ func (_m *apiQuerierMock) RegisterNomadJob(job *api.Job) (string, error) {
} }
// SetJobScale provides a mock function with given fields: jobID, count, reason // SetJobScale provides a mock function with given fields: jobID, count, reason
func (_m *apiQuerierMock) SetJobScale(jobId string, count uint, reason string) error { func (_m *apiQuerierMock) SetJobScale(jobID string, count uint, reason string) error {
ret := _m.Called(jobId, count, reason) ret := _m.Called(jobID, count, reason)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, uint, string) error); ok { if rf, ok := ret.Get(0).(func(string, uint, string) error); ok {
r0 = rf(jobId, count, reason) r0 = rf(jobID, count, reason)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@ -202,13 +202,13 @@ func (_m *apiQuerierMock) allocation(jobID string) (*api.Allocation, error) {
return r0, r1 return r0, r1
} }
// init provides a mock function with given fields: nomadURL, nomadNamespace // init provides a mock function with given fields: nomadURL, nomadNamespace, nomadToken
func (_m *apiQuerierMock) init(nomadURL *url.URL, nomadNamespace string) error { func (_m *apiQuerierMock) init(nomadURL *url.URL, nomadNamespace string, nomadToken string) error {
ret := _m.Called(nomadURL, nomadNamespace) ret := _m.Called(nomadURL, nomadNamespace, nomadToken)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(*url.URL, string) error); ok { if rf, ok := ret.Get(0).(func(*url.URL, string, string) error); ok {
r0 = rf(nomadURL, nomadNamespace) r0 = rf(nomadURL, nomadNamespace, nomadToken)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

View File

@ -42,13 +42,13 @@ func (_m *ExecutorAPIMock) AllocationStream(ctx context.Context) (<-chan *api.Ev
return r0, r1 return r0, r1
} }
// DeleteRunner provides a mock function with given fields: runnerId // DeleteRunner provides a mock function with given fields: runnerID
func (_m *ExecutorAPIMock) DeleteRunner(runnerId string) error { func (_m *ExecutorAPIMock) DeleteRunner(runnerID string) error {
ret := _m.Called(runnerId) ret := _m.Called(runnerID)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok { if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(runnerId) r0 = rf(runnerID)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@ -122,19 +122,19 @@ func (_m *ExecutorAPIMock) ExecuteCommand(allocationID string, ctx context.Conte
} }
// JobScale provides a mock function with given fields: jobID // JobScale provides a mock function with given fields: jobID
func (_m *ExecutorAPIMock) JobScale(jobId string) (uint, error) { func (_m *ExecutorAPIMock) JobScale(jobID string) (uint, error) {
ret := _m.Called(jobId) ret := _m.Called(jobID)
var r0 uint var r0 uint
if rf, ok := ret.Get(0).(func(string) uint); ok { if rf, ok := ret.Get(0).(func(string) uint); ok {
r0 = rf(jobId) r0 = rf(jobID)
} else { } else {
r0 = ret.Get(0).(uint) r0 = ret.Get(0).(uint)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(jobId) r1 = rf(jobID)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@ -234,7 +234,7 @@ func (_m *ExecutorAPIMock) LoadRunnerJobs(environmentID string) ([]*api.Job, err
return r0, r1 return r0, r1
} }
// LoadRunnerPorts provides a mock function with given fields: runnerID // LoadRunnerPortMappings provides a mock function with given fields: runnerID
func (_m *ExecutorAPIMock) LoadRunnerPortMappings(runnerID string) ([]api.PortMapping, error) { func (_m *ExecutorAPIMock) LoadRunnerPortMappings(runnerID string) ([]api.PortMapping, error) {
ret := _m.Called(runnerID) ret := _m.Called(runnerID)
@ -344,12 +344,12 @@ func (_m *ExecutorAPIMock) RegisterTemplateJob(defaultJob *api.Job, id string, p
} }
// SetJobScale provides a mock function with given fields: jobID, count, reason // SetJobScale provides a mock function with given fields: jobID, count, reason
func (_m *ExecutorAPIMock) SetJobScale(jobId string, count uint, reason string) error { func (_m *ExecutorAPIMock) SetJobScale(jobID string, count uint, reason string) error {
ret := _m.Called(jobId, count, reason) ret := _m.Called(jobID, count, reason)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, uint, string) error); ok { if rf, ok := ret.Get(0).(func(string, uint, string) error); ok {
r0 = rf(jobId, count, reason) r0 = rf(jobID, count, reason)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@ -394,13 +394,13 @@ func (_m *ExecutorAPIMock) allocation(jobID string) (*api.Allocation, error) {
return r0, r1 return r0, r1
} }
// init provides a mock function with given fields: nomadURL, nomadNamespace // init provides a mock function with given fields: nomadURL, nomadNamespace, nomadToken
func (_m *ExecutorAPIMock) init(nomadURL *url.URL, nomadNamespace string) error { func (_m *ExecutorAPIMock) init(nomadURL *url.URL, nomadNamespace string, nomadToken string) error {
ret := _m.Called(nomadURL, nomadNamespace) ret := _m.Called(nomadURL, nomadNamespace, nomadToken)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(*url.URL, string) error); ok { if rf, ok := ret.Get(0).(func(*url.URL, string, string) error); ok {
r0 = rf(nomadURL, nomadNamespace) r0 = rf(nomadURL, nomadNamespace, nomadToken)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

View File

@ -81,15 +81,15 @@ type APIClient struct {
// NewExecutorAPI creates a new api client. // NewExecutorAPI creates a new api client.
// One client is usually sufficient for the complete runtime of the API. // One client is usually sufficient for the complete runtime of the API.
func NewExecutorAPI(nomadURL *url.URL, nomadNamespace string) (ExecutorAPI, error) { func NewExecutorAPI(nomadURL *url.URL, nomadNamespace, nomadToken string) (ExecutorAPI, error) {
client := &APIClient{apiQuerier: &nomadAPIClient{}} client := &APIClient{apiQuerier: &nomadAPIClient{}}
err := client.init(nomadURL, nomadNamespace) err := client.init(nomadURL, nomadNamespace, nomadToken)
return client, err return client, err
} }
// init prepares an apiClient to be able to communicate to a provided Nomad API. // init prepares an apiClient to be able to communicate to a provided Nomad API.
func (a *APIClient) init(nomadURL *url.URL, nomadNamespace string) error { func (a *APIClient) init(nomadURL *url.URL, nomadNamespace, nomadToken string) error {
if err := a.apiQuerier.init(nomadURL, nomadNamespace); err != nil { if err := a.apiQuerier.init(nomadURL, nomadNamespace, nomadToken); err != nil {
return fmt.Errorf("error initializing API querier: %w", err) return fmt.Errorf("error initializing API querier: %w", err)
} }
return nil return nil

View File

@ -130,10 +130,11 @@ var (
) )
const TestNamespace = "unit-tests" const TestNamespace = "unit-tests"
const TestNomadToken = "n0m4d-t0k3n"
func TestApiClient_init(t *testing.T) { func TestApiClient_init(t *testing.T) {
client := &APIClient{apiQuerier: &nomadAPIClient{}} client := &APIClient{apiQuerier: &nomadAPIClient{}}
err := client.init(&TestURL, TestNamespace) err := client.init(&TestURL, TestNamespace, TestNomadToken)
require.Nil(t, err) require.Nil(t, err)
} }
@ -142,16 +143,16 @@ func TestApiClientCanNotBeInitializedWithInvalidUrl(t *testing.T) {
err := client.init(&url.URL{ err := client.init(&url.URL{
Scheme: "http", Scheme: "http",
Host: "http://127.0.0.1:4646", Host: "http://127.0.0.1:4646",
}, TestNamespace) }, TestNamespace, TestNomadToken)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestNewExecutorApiCanBeCreatedWithoutError(t *testing.T) { func TestNewExecutorApiCanBeCreatedWithoutError(t *testing.T) {
expectedClient := &APIClient{apiQuerier: &nomadAPIClient{}} expectedClient := &APIClient{apiQuerier: &nomadAPIClient{}}
err := expectedClient.init(&TestURL, TestNamespace) err := expectedClient.init(&TestURL, TestNamespace, TestNomadToken)
require.Nil(t, err) require.Nil(t, err)
_, err = NewExecutorAPI(&TestURL, TestNamespace) _, err = NewExecutorAPI(&TestURL, TestNamespace, TestNomadToken)
require.Nil(t, err) require.Nil(t, err)
} }