Verified Commit f31cf6d1 authored by Zubeen's avatar Zubeen 🤖 Committed by GitLab
Browse files

feat(runners): add reset by token and router discovery endpoints

Changelog: Improvements
parent 7f1dadc7
Loading
Loading
Loading
Loading
+50 −0
Changes for runners.go: 50 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -33,7 +33,9 @@ var (
	routeRunnersIDJobs                           = route("runners/%s/jobs")
	routeRunnersIDManagers                       = route("runners/%s/managers")
	routeRunnersIDResetAuthenticationToken       = route("runners/%d/reset_authentication_token")
	routeRunnersResetAuthenticationToken         = route("runners/reset_authentication_token")
	routeRunnersResetRegistrationToken           = route("runners/reset_registration_token")
	routeRunnersRouterDiscovery                  = route("runners/router/discovery")
	routeRunnersVerify                           = route("runners/verify")
)

@@ -122,6 +124,20 @@ type (
		// GitLab API docs:
		// https://docs.gitlab.com/api/runners/#reset-runners-authentication-token-by-using-the-runner-id
		ResetRunnerAuthenticationToken(rid int64, options ...RequestOptionFunc) (*RunnerAuthenticationToken, *Response, error)
		// ResetRunnerAuthenticationTokenByToken resets a runner's authentication
		// token by using the current token as input.
		//
		// GitLab API docs:
		// https://docs.gitlab.com/api/runners/#reset-runners-authentication-token-by-using-the-current-token
		ResetRunnerAuthenticationTokenByToken(opt *ResetRunnerAuthenticationTokenByTokenOptions, options ...RequestOptionFunc) (*RunnerAuthenticationToken, *Response, error)
		// GetRunnerRouterDiscovery gets the Job Router discovery information for
		// the runner with the given authentication token. The Job Router is behind
		// feature flags and is disabled by default; the API returns 501 if it is
		// not available.
		//
		// GitLab API docs:
		// https://docs.gitlab.com/api/runners/#discover-job-router-information
		GetRunnerRouterDiscovery(runnerToken string, options ...RequestOptionFunc) (*RunnerRouterDiscovery, *Response, error)

		// Deprecated: for removal in GitLab 20.0, see https://docs.gitlab.com/ci/runners/new_creation_workflow/ instead
		ResetInstanceRunnerRegistrationToken(options ...RequestOptionFunc) (*RunnerRegistrationToken, *Response, error)
@@ -624,3 +640,37 @@ func (s *RunnersService) ResetRunnerAuthenticationToken(rid int64, options ...Re
	}
	return res, resp, nil
}

// ResetRunnerAuthenticationTokenByTokenOptions represents the available
// ResetRunnerAuthenticationTokenByToken() options.
//
// GitLab API docs:
// https://docs.gitlab.com/api/runners/#reset-runners-authentication-token-by-using-the-current-token
type ResetRunnerAuthenticationTokenByTokenOptions struct {
	Token *string `url:"token" json:"token"`
}

func (s *RunnersService) ResetRunnerAuthenticationTokenByToken(opt *ResetRunnerAuthenticationTokenByTokenOptions, options ...RequestOptionFunc) (*RunnerAuthenticationToken, *Response, error) {
	return do[*RunnerAuthenticationToken](s.client,
		withMethod(http.MethodPost),
		withPath(routeRunnersResetAuthenticationToken),
		withAPIOpts(opt),
		withRequestOpts(options...),
	)
}

// RunnerRouterDiscovery represents the Job Router discovery information of a
// runner.
//
// GitLab API docs:
// https://docs.gitlab.com/api/runners/#discover-job-router-information
type RunnerRouterDiscovery struct {
	ServerURL string `json:"server_url"`
}

func (s *RunnersService) GetRunnerRouterDiscovery(runnerToken string, options ...RequestOptionFunc) (*RunnerRouterDiscovery, *Response, error) {
	return do[*RunnerRouterDiscovery](s.client,
		withPath(routeRunnersRouterDiscovery),
		withRequestOpts(append([]RequestOptionFunc{WithHeader("Runner-Token", runnerToken)}, options...)...),
	)
}
+76 −0
Changes for runners_test.go: 76 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -483,3 +483,79 @@ func TestResetRunnerAuthenticationToken(t *testing.T) {
	assert.Equal(t, want, token)
	assert.Equal(t, 201, resp.StatusCode)
}

func TestResetRunnerAuthenticationTokenByToken(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	// GIVEN a server that resets a runner's token using its current token
	mux.HandleFunc("/api/v4/runners/reset_authentication_token", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPost)
		testBodyJSON(t, r, map[string]any{"token": "current-token"})
		w.WriteHeader(http.StatusCreated)
		fmt.Fprint(w, `{
			"token": "6337ff461c94fd3fa32ba3b1ff4125",
			"token_expires_at": "2021-09-27T21:05:03.203Z"
		}`)
	})

	// WHEN resetting the token by token
	opt := &ResetRunnerAuthenticationTokenByTokenOptions{Token: new("current-token")}
	token, resp, err := client.Runners.ResetRunnerAuthenticationTokenByToken(opt)

	// THEN the new token is returned
	require.NoError(t, err)
	want := &RunnerAuthenticationToken{
		Token:          new("6337ff461c94fd3fa32ba3b1ff4125"),
		TokenExpiresAt: new(time.Date(2021, time.September, 27, 21, 5, 3, 203000000, time.UTC)),
	}
	assert.Equal(t, want, token)
	assert.Equal(t, http.StatusCreated, resp.StatusCode)

	// WHEN a request option fails
	token, resp, err = client.Runners.ResetRunnerAuthenticationTokenByToken(opt, errorOption)

	// THEN the error is returned
	require.ErrorIs(t, err, errRequestOptionFunc)
	assert.Nil(t, resp)
	assert.Nil(t, token)
}

func TestGetRunnerRouterDiscovery(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	// GIVEN a server that returns Job Router info for a valid runner token
	mux.HandleFunc("/api/v4/runners/router/discovery", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		if r.Header.Get("Runner-Token") != "runner-token" {
			w.WriteHeader(http.StatusForbidden)
			return
		}
		fmt.Fprint(w, `{"server_url": "wss://kas.example.com"}`)
	})

	// WHEN getting the discovery information
	discovery, resp, err := client.Runners.GetRunnerRouterDiscovery("runner-token")

	// THEN the Job Router URL is returned
	require.NoError(t, err)
	require.NotNil(t, resp)
	assert.Equal(t, &RunnerRouterDiscovery{ServerURL: "wss://kas.example.com"}, discovery)

	// WHEN the runner token is invalid
	discovery, resp, err = client.Runners.GetRunnerRouterDiscovery("wrong")

	// THEN a 403 error is returned
	require.Error(t, err)
	assert.Nil(t, discovery)
	assert.Equal(t, http.StatusForbidden, resp.StatusCode)

	// WHEN a request option fails
	discovery, resp, err = client.Runners.GetRunnerRouterDiscovery("runner-token", errorOption)

	// THEN the error is returned
	require.ErrorIs(t, err, errRequestOptionFunc)
	assert.Nil(t, resp)
	assert.Nil(t, discovery)
}
+90 −0
Changes for testing/runners_mock.go: 90 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -261,6 +261,51 @@ func (c *MockRunnersServiceInterfaceGetRunnerDetailsCall) DoAndReturn(f func(any
	return c
}

// GetRunnerRouterDiscovery mocks base method.
func (m *MockRunnersServiceInterface) GetRunnerRouterDiscovery(runnerToken string, options ...gitlab.RequestOptionFunc) (*gitlab.RunnerRouterDiscovery, *gitlab.Response, error) {
	m.ctrl.T.Helper()
	varargs := []any{runnerToken}
	for _, a := range options {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "GetRunnerRouterDiscovery", varargs...)
	ret0, _ := ret[0].(*gitlab.RunnerRouterDiscovery)
	ret1, _ := ret[1].(*gitlab.Response)
	ret2, _ := ret[2].(error)
	return ret0, ret1, ret2
}

// GetRunnerRouterDiscovery indicates an expected call of GetRunnerRouterDiscovery.
func (mr *MockRunnersServiceInterfaceMockRecorder) GetRunnerRouterDiscovery(runnerToken any, options ...any) *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall {
	mr.mock.ctrl.T.Helper()
	varargs := append([]any{runnerToken}, options...)
	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRunnerRouterDiscovery", reflect.TypeOf((*MockRunnersServiceInterface)(nil).GetRunnerRouterDiscovery), varargs...)
	return &MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall{Call: call}
}

// MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall wrap *gomock.Call
type MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall struct {
	*gomock.Call
}

// Return rewrite *gomock.Call.Return
func (c *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall) Return(arg0 *gitlab.RunnerRouterDiscovery, arg1 *gitlab.Response, arg2 error) *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall {
	c.Call = c.Call.Return(arg0, arg1, arg2)
	return c
}

// Do rewrite *gomock.Call.Do
func (c *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall) Do(f func(string, ...gitlab.RequestOptionFunc) (*gitlab.RunnerRouterDiscovery, *gitlab.Response, error)) *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall {
	c.Call = c.Call.Do(f)
	return c
}

// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall) DoAndReturn(f func(string, ...gitlab.RequestOptionFunc) (*gitlab.RunnerRouterDiscovery, *gitlab.Response, error)) *MockRunnersServiceInterfaceGetRunnerRouterDiscoveryCall {
	c.Call = c.Call.DoAndReturn(f)
	return c
}

// ListAllRunners mocks base method.
func (m *MockRunnersServiceInterface) ListAllRunners(opt *gitlab.ListRunnersOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Runner, *gitlab.Response, error) {
	m.ctrl.T.Helper()
@@ -799,6 +844,51 @@ func (c *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenCall) DoAndRet
	return c
}

// ResetRunnerAuthenticationTokenByToken mocks base method.
func (m *MockRunnersServiceInterface) ResetRunnerAuthenticationTokenByToken(opt *gitlab.ResetRunnerAuthenticationTokenByTokenOptions, options ...gitlab.RequestOptionFunc) (*gitlab.RunnerAuthenticationToken, *gitlab.Response, error) {
	m.ctrl.T.Helper()
	varargs := []any{opt}
	for _, a := range options {
		varargs = append(varargs, a)
	}
	ret := m.ctrl.Call(m, "ResetRunnerAuthenticationTokenByToken", varargs...)
	ret0, _ := ret[0].(*gitlab.RunnerAuthenticationToken)
	ret1, _ := ret[1].(*gitlab.Response)
	ret2, _ := ret[2].(error)
	return ret0, ret1, ret2
}

// ResetRunnerAuthenticationTokenByToken indicates an expected call of ResetRunnerAuthenticationTokenByToken.
func (mr *MockRunnersServiceInterfaceMockRecorder) ResetRunnerAuthenticationTokenByToken(opt any, options ...any) *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall {
	mr.mock.ctrl.T.Helper()
	varargs := append([]any{opt}, options...)
	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetRunnerAuthenticationTokenByToken", reflect.TypeOf((*MockRunnersServiceInterface)(nil).ResetRunnerAuthenticationTokenByToken), varargs...)
	return &MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall{Call: call}
}

// MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall wrap *gomock.Call
type MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall struct {
	*gomock.Call
}

// Return rewrite *gomock.Call.Return
func (c *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall) Return(arg0 *gitlab.RunnerAuthenticationToken, arg1 *gitlab.Response, arg2 error) *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall {
	c.Call = c.Call.Return(arg0, arg1, arg2)
	return c
}

// Do rewrite *gomock.Call.Do
func (c *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall) Do(f func(*gitlab.ResetRunnerAuthenticationTokenByTokenOptions, ...gitlab.RequestOptionFunc) (*gitlab.RunnerAuthenticationToken, *gitlab.Response, error)) *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall {
	c.Call = c.Call.Do(f)
	return c
}

// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall) DoAndReturn(f func(*gitlab.ResetRunnerAuthenticationTokenByTokenOptions, ...gitlab.RequestOptionFunc) (*gitlab.RunnerAuthenticationToken, *gitlab.Response, error)) *MockRunnersServiceInterfaceResetRunnerAuthenticationTokenByTokenCall {
	c.Call = c.Call.DoAndReturn(f)
	return c
}

// UpdateRunnerDetails mocks base method.
func (m *MockRunnersServiceInterface) UpdateRunnerDetails(rid any, opt *gitlab.UpdateRunnerDetailsOptions, options ...gitlab.RequestOptionFunc) (*gitlab.RunnerDetails, *gitlab.Response, error) {
	m.ctrl.T.Helper()