Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 19 additions & 1 deletion docs/docs/gen/api/post-node-container-docker.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Create a new container on the target node. Returns a job ID for tr
sidebar_label: "Create a container"
hide_title: true
hide_table_of_contents: true
api: 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
api: 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
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
Expand Down Expand Up @@ -134,6 +134,24 @@ Create a new container on the target node. Returns a job ID for tracking the asy
schema={{"type":"string","description":"Optional name for the container.","example":"my-nginx","x-oapi-codegen-extra-tags":{"validate":"omitempty,min=1"}}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"hostname"}
required={false}
schemaName={"string"}
qualifierMessage={undefined}
schema={{"type":"string","description":"Container hostname.","example":"web-01","x-oapi-codegen-extra-tags":{"validate":"omitempty,min=1,max=253"}}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"dns"}
required={false}
schemaName={"string[]"}
qualifierMessage={undefined}
schema={{"type":"array","items":{"type":"string"},"description":"Custom DNS servers for the container.","example":["8.8.8.8","8.8.4.4"],"x-oapi-codegen-extra-tags":{"validate":"omitempty,dive,ip"}}}
>

</SchemaItem><SchemaItem
collapsible={false}
name={"command"}
Expand Down
2 changes: 2 additions & 0 deletions internal/agent/processor_docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ func processDockerCreate(
result, err := dockerProvider.Create(ctx, dockerProv.CreateParams{
Image: data.Image,
Name: data.Name,
Hostname: data.Hostname,
DNS: data.DNS,
Command: data.Command,
Env: data.Env,
Ports: ports,
Expand Down
34 changes: 34 additions & 0 deletions internal/agent/processor_docker_public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ func (s *ProcessorDockerPublicTestSuite) TestProcessDockerOperation() {
s.Equal(true, r["changed"])
},
},
{
name: "successful container create with hostname and dns",
jobRequest: job.Request{
Type: job.TypeModify,
Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(
`{"image":"nginx:latest","name":"web","hostname":"web-01","dns":["8.8.8.8","8.8.4.4"]}`,
),
},
setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Create(gomock.Any(), dockerProv.CreateParams{
Image: "nginx:latest",
Name: "web",
Hostname: "web-01",
DNS: []string{"8.8.8.8", "8.8.4.4"},
}).
Return(&dockerProv.Container{
ID: "ghi789",
Name: "web",
Image: "nginx:latest",
State: "created",
Changed: true,
}, nil)
},
validate: func(result json.RawMessage) {
var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Equal("ghi789", r["id"])
s.Equal(true, r["changed"])
},
},
{
name: "unsupported docker operation",
jobRequest: job.Request{
Expand Down
16 changes: 16 additions & 0 deletions internal/controller/api/gen/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6891,6 +6891,22 @@ components:
example: my-nginx
x-oapi-codegen-extra-tags:
validate: omitempty,min=1
hostname:
type: string
description: Container hostname.
example: web-01
x-oapi-codegen-extra-tags:
validate: omitempty,min=1,max=253
dns:
type: array
items:
type: string
description: Custom DNS servers for the container.
example:
- 8.8.8.8
- 8.8.4.4
x-oapi-codegen-extra-tags:
validate: omitempty,dive,ip
command:
type: array
description: Command to run in the container.
Expand Down
6 changes: 6 additions & 0 deletions internal/controller/api/node/docker/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ func (s *Container) PostNodeContainerDocker(
if request.Body.Name != nil {
data.Name = *request.Body.Name
}
if request.Body.Hostname != nil {
data.Hostname = *request.Body.Hostname
}
if request.Body.Dns != nil {
data.DNS = *request.Body.Dns
}
if request.Body.AutoStart != nil {
data.AutoStart = *request.Body.AutoStart
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,53 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerDocker() {
s.Require().NotNil(r.Error)
},
},
{
name: "success with hostname and dns",
request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
Hostname: strPtr("web-01"),
Dns: &[]string{"8.8.8.8", "8.8.4.4"},
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
Modify(
gomock.Any(),
"server1",
"docker",
job.OperationDockerCreate,
gomock.Any(),
).
DoAndReturn(func(
_ interface{},
_ string,
_ string,
_ job.OperationType,
data interface{},
) (string, *job.Response, error) {
d, ok := data.(*job.DockerCreateData)
s.True(ok)
s.Equal("web-01", d.Hostname)
s.Equal([]string{"8.8.8.8", "8.8.4.4"}, d.DNS)
return "550e8400-e29b-41d4-a716-446655440000", &job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
Changed: boolPtr(true),
Data: json.RawMessage(`{"id":"abc123"}`),
}, nil
})
},
validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
r, ok := resp.(gen.PostNodeContainerDocker202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
s.Require().NotNil(r.Results[0].Id)
s.Equal("abc123", *r.Results[0].Id)
},
},
{
name: "success with explicit auto_start false",
request: gen.PostNodeContainerDockerRequestObject{
Expand Down Expand Up @@ -465,6 +512,26 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerDockerValidationHT
wantCode: http.StatusBadRequest,
wantContains: []string{`"error"`, "Image", "required"},
},
{
name: "when hostname exceeds max length",
path: "/node/server1/container/docker",
body: `{"image":"nginx:latest","hostname":"` + strings.Repeat("a", 254) + `"}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
wantCode: http.StatusBadRequest,
wantContains: []string{`"error"`, "Hostname", "max"},
},
{
name: "when dns contains invalid ip",
path: "/node/server1/container/docker",
body: `{"image":"nginx:latest","dns":["not-an-ip"]}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
wantCode: http.StatusBadRequest,
wantContains: []string{`"error"`, "Dns", "ip"},
},
{
name: "when target agent not found",
path: "/node/nonexistent/container/docker",
Expand Down
14 changes: 14 additions & 0 deletions internal/controller/api/node/docker/gen/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,20 @@ components:
example: "my-nginx"
x-oapi-codegen-extra-tags:
validate: "omitempty,min=1"
hostname:
type: string
description: Container hostname.
example: "web-01"
x-oapi-codegen-extra-tags:
validate: "omitempty,min=1,max=253"
dns:
type: array
items:
type: string
description: Custom DNS servers for the container.
example: ["8.8.8.8", "8.8.4.4"]
x-oapi-codegen-extra-tags:
validate: "omitempty,dive,ip"
command:
type: array
description: Command to run in the container.
Expand Down
6 changes: 6 additions & 0 deletions internal/controller/api/node/docker/gen/docker.gen.go

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

2 changes: 2 additions & 0 deletions internal/job/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ type CommandShellData struct {
type DockerCreateData struct {
Image string `json:"image"`
Name string `json:"name,omitempty"`
Hostname string `json:"hostname,omitempty"`
DNS []string `json:"dns,omitempty"`
Command []string `json:"command,omitempty"`
Env map[string]string `json:"env,omitempty"`
Ports []PortMapping `json:"ports,omitempty"`
Expand Down
8 changes: 8 additions & 0 deletions internal/provider/container/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func (d *Client) Create(
Image: params.Image,
}

if params.Hostname != "" {
config.Hostname = params.Hostname
}

if len(params.Command) > 0 {
config.Cmd = params.Command
}
Expand All @@ -88,6 +92,10 @@ func (d *Client) Create(
// Build host configuration
hostConfig := &container.HostConfig{}

if len(params.DNS) > 0 {
hostConfig.DNS = params.DNS
}

// Convert port mappings
if len(params.Ports) > 0 {
portBindings := nat.PortMap{}
Expand Down
Loading
Loading