diff --git a/Makefile b/Makefile index c399b57..9e1a3ee 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ golangci-lint: ## Lint the source code using golangci-lint lint: golangci-lint ## Lint the source code using all linters .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 @mockery \ --name=$(name) \ diff --git a/cmd/poseidon/main.go b/cmd/poseidon/main.go index e5f1fbf..e577b87 100644 --- a/cmd/poseidon/main.go +++ b/cmd/poseidon/main.go @@ -45,7 +45,11 @@ func runServer(server *http.Server) { func initServer() *http.Server { // 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 { log.WithError(err).WithField("nomad url", config.Config.NomadAPIURL()).Fatal("Error parsing the nomad url") } diff --git a/internal/nomad/api_querier.go b/internal/nomad/api_querier.go index c6ae626..6e5b3fc 100644 --- a/internal/nomad/api_querier.go +++ b/internal/nomad/api_querier.go @@ -16,7 +16,7 @@ var ( // apiQuerier provides access to the Nomad functionality. type apiQuerier interface { // 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() (list []*nomadApi.JobListStub, err error) @@ -61,11 +61,12 @@ type nomadAPIClient struct { 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{ Address: nomadURL.String(), TLSConfig: &nomadApi.TLSConfig{}, Namespace: nomadNamespace, + SecretID: nomadToken, }) if err != nil { 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( ctx, 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, nc.queryOptions()) diff --git a/internal/nomad/api_querier_mock.go b/internal/nomad/api_querier_mock.go index b4e00c1..faa8d16 100644 --- a/internal/nomad/api_querier_mock.go +++ b/internal/nomad/api_querier_mock.go @@ -42,13 +42,13 @@ func (_m *apiQuerierMock) AllocationStream(ctx context.Context) (<-chan *api.Eve return r0, r1 } -// DeleteRunner provides a mock function with given fields: runnerId -func (_m *apiQuerierMock) DeleteRunner(runnerId string) error { - ret := _m.Called(runnerId) +// DeleteRunner provides a mock function with given fields: runnerID +func (_m *apiQuerierMock) DeleteRunner(runnerID string) error { + ret := _m.Called(runnerID) var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(runnerId) + r0 = rf(runnerID) } else { 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 -func (_m *apiQuerierMock) JobScale(jobId string) (uint, error) { - ret := _m.Called(jobId) +func (_m *apiQuerierMock) JobScale(jobID string) (uint, error) { + ret := _m.Called(jobID) var r0 uint if rf, ok := ret.Get(0).(func(string) uint); ok { - r0 = rf(jobId) + r0 = rf(jobID) } else { r0 = ret.Get(0).(uint) } var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(jobId) + r1 = rf(jobID) } else { 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 -func (_m *apiQuerierMock) SetJobScale(jobId string, count uint, reason string) error { - ret := _m.Called(jobId, count, reason) +func (_m *apiQuerierMock) SetJobScale(jobID string, count uint, reason string) error { + ret := _m.Called(jobID, count, reason) var r0 error if rf, ok := ret.Get(0).(func(string, uint, string) error); ok { - r0 = rf(jobId, count, reason) + r0 = rf(jobID, count, reason) } else { r0 = ret.Error(0) } @@ -202,13 +202,13 @@ func (_m *apiQuerierMock) allocation(jobID string) (*api.Allocation, error) { return r0, r1 } -// init provides a mock function with given fields: nomadURL, nomadNamespace -func (_m *apiQuerierMock) init(nomadURL *url.URL, nomadNamespace string) error { - ret := _m.Called(nomadURL, nomadNamespace) +// init provides a mock function with given fields: nomadURL, nomadNamespace, nomadToken +func (_m *apiQuerierMock) init(nomadURL *url.URL, nomadNamespace string, nomadToken string) error { + ret := _m.Called(nomadURL, nomadNamespace, nomadToken) var r0 error - if rf, ok := ret.Get(0).(func(*url.URL, string) error); ok { - r0 = rf(nomadURL, nomadNamespace) + if rf, ok := ret.Get(0).(func(*url.URL, string, string) error); ok { + r0 = rf(nomadURL, nomadNamespace, nomadToken) } else { r0 = ret.Error(0) } diff --git a/internal/nomad/executor_api_mock.go b/internal/nomad/executor_api_mock.go index de53d2d..17e5a5a 100644 --- a/internal/nomad/executor_api_mock.go +++ b/internal/nomad/executor_api_mock.go @@ -42,13 +42,13 @@ func (_m *ExecutorAPIMock) AllocationStream(ctx context.Context) (<-chan *api.Ev return r0, r1 } -// DeleteRunner provides a mock function with given fields: runnerId -func (_m *ExecutorAPIMock) DeleteRunner(runnerId string) error { - ret := _m.Called(runnerId) +// DeleteRunner provides a mock function with given fields: runnerID +func (_m *ExecutorAPIMock) DeleteRunner(runnerID string) error { + ret := _m.Called(runnerID) var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(runnerId) + r0 = rf(runnerID) } else { 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 -func (_m *ExecutorAPIMock) JobScale(jobId string) (uint, error) { - ret := _m.Called(jobId) +func (_m *ExecutorAPIMock) JobScale(jobID string) (uint, error) { + ret := _m.Called(jobID) var r0 uint if rf, ok := ret.Get(0).(func(string) uint); ok { - r0 = rf(jobId) + r0 = rf(jobID) } else { r0 = ret.Get(0).(uint) } var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(jobId) + r1 = rf(jobID) } else { r1 = ret.Error(1) } @@ -234,7 +234,7 @@ func (_m *ExecutorAPIMock) LoadRunnerJobs(environmentID string) ([]*api.Job, err 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) { 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 -func (_m *ExecutorAPIMock) SetJobScale(jobId string, count uint, reason string) error { - ret := _m.Called(jobId, count, reason) +func (_m *ExecutorAPIMock) SetJobScale(jobID string, count uint, reason string) error { + ret := _m.Called(jobID, count, reason) var r0 error if rf, ok := ret.Get(0).(func(string, uint, string) error); ok { - r0 = rf(jobId, count, reason) + r0 = rf(jobID, count, reason) } else { r0 = ret.Error(0) } @@ -394,13 +394,13 @@ func (_m *ExecutorAPIMock) allocation(jobID string) (*api.Allocation, error) { return r0, r1 } -// init provides a mock function with given fields: nomadURL, nomadNamespace -func (_m *ExecutorAPIMock) init(nomadURL *url.URL, nomadNamespace string) error { - ret := _m.Called(nomadURL, nomadNamespace) +// init provides a mock function with given fields: nomadURL, nomadNamespace, nomadToken +func (_m *ExecutorAPIMock) init(nomadURL *url.URL, nomadNamespace string, nomadToken string) error { + ret := _m.Called(nomadURL, nomadNamespace, nomadToken) var r0 error - if rf, ok := ret.Get(0).(func(*url.URL, string) error); ok { - r0 = rf(nomadURL, nomadNamespace) + if rf, ok := ret.Get(0).(func(*url.URL, string, string) error); ok { + r0 = rf(nomadURL, nomadNamespace, nomadToken) } else { r0 = ret.Error(0) } diff --git a/internal/nomad/nomad.go b/internal/nomad/nomad.go index 7ff2120..8881083 100644 --- a/internal/nomad/nomad.go +++ b/internal/nomad/nomad.go @@ -81,15 +81,15 @@ type APIClient struct { // NewExecutorAPI creates a new api client. // 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{}} - err := client.init(nomadURL, nomadNamespace) + err := client.init(nomadURL, nomadNamespace, nomadToken) return client, err } // init prepares an apiClient to be able to communicate to a provided Nomad API. -func (a *APIClient) init(nomadURL *url.URL, nomadNamespace string) error { - if err := a.apiQuerier.init(nomadURL, nomadNamespace); err != nil { +func (a *APIClient) init(nomadURL *url.URL, nomadNamespace, nomadToken string) error { + if err := a.apiQuerier.init(nomadURL, nomadNamespace, nomadToken); err != nil { return fmt.Errorf("error initializing API querier: %w", err) } return nil diff --git a/internal/nomad/nomad_test.go b/internal/nomad/nomad_test.go index f8f3002..e89464e 100644 --- a/internal/nomad/nomad_test.go +++ b/internal/nomad/nomad_test.go @@ -130,10 +130,11 @@ var ( ) const TestNamespace = "unit-tests" +const TestNomadToken = "n0m4d-t0k3n" func TestApiClient_init(t *testing.T) { client := &APIClient{apiQuerier: &nomadAPIClient{}} - err := client.init(&TestURL, TestNamespace) + err := client.init(&TestURL, TestNamespace, TestNomadToken) require.Nil(t, err) } @@ -142,16 +143,16 @@ func TestApiClientCanNotBeInitializedWithInvalidUrl(t *testing.T) { err := client.init(&url.URL{ Scheme: "http", Host: "http://127.0.0.1:4646", - }, TestNamespace) + }, TestNamespace, TestNomadToken) assert.NotNil(t, err) } func TestNewExecutorApiCanBeCreatedWithoutError(t *testing.T) { expectedClient := &APIClient{apiQuerier: &nomadAPIClient{}} - err := expectedClient.init(&TestURL, TestNamespace) + err := expectedClient.init(&TestURL, TestNamespace, TestNomadToken) require.Nil(t, err) - _, err = NewExecutorAPI(&TestURL, TestNamespace) + _, err = NewExecutorAPI(&TestURL, TestNamespace, TestNomadToken) require.Nil(t, err) }