mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 15:59:41 +02:00
feat(schedules): add the schedule API
* feat(jobs): add job service interface * feat(jobs): create job execution api * style(jobs): remove comment * feat(jobs): add bindings * feat(jobs): validate payload different cases * refactor(jobs): rename endpointJob method * refactor(jobs): return original error * feat(jobs): pull image before creating container * feat(jobs): run jobs with sh * style(jobs): remove comment * refactor(jobs): change error names * feat(jobs): sync pull image * fix(jobs): close image reader after error check * style(jobs): remove comment and add docs * refactor(jobs): inline script command * fix(jobs): handle pul image error * refactor(jobs): handle image pull output * fix(docker): set http client timeout to 100s * feat(api): create schedule type * feat(agent): add basic schedule api * feat(schedules): add schedule service in bolt * feat(schedule): add schedule service to handler * feat(schedule): add and list schedules from db * feat(agent): get schedule from db * feat(schedule): update schedule in db * feat(agent): delete schedule * fix(bolt): remove sync method from scheduleService * feat(schedules): save/delete script in fs * feat(schedules): schedules cron service implementation * feat(schedule): integrate handler with cron * feat(schedules): schedules API overhaul * refactor(project): remove .idea folder * fix(schedules): fix script task execute call * refactor(schedules): refactor/fix golint issues * refactor(schedules): update SnapshotTask documentation * refactor(schedules): validate image name in ScheduleCreate operation
This commit is contained in:
parent
e94d6ad6b2
commit
dbbea0a20f
20 changed files with 873 additions and 174 deletions
103
api/docker/job.go
Normal file
103
api/docker/job.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/portainer/portainer"
|
||||
"github.com/portainer/portainer/archive"
|
||||
)
|
||||
|
||||
// JobService represents a service that handles the execution of jobs
|
||||
type JobService struct {
|
||||
DockerClientFactory *ClientFactory
|
||||
}
|
||||
|
||||
// NewJobService returns a pointer to a new job service
|
||||
func NewJobService(dockerClientFactory *ClientFactory) *JobService {
|
||||
return &JobService{
|
||||
DockerClientFactory: dockerClientFactory,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute will execute a script on the endpoint host with the supplied image as a container
|
||||
func (service *JobService) Execute(endpoint *portainer.Endpoint, nodeName, image string, script []byte) error {
|
||||
buffer, err := archive.TarFileInBuffer(script, "script.sh", 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cli, err := service.DockerClientFactory.CreateClient(endpoint, nodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
err = pullImage(cli, image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
containerConfig := &container.Config{
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
WorkingDir: "/tmp",
|
||||
Image: image,
|
||||
Labels: map[string]string{
|
||||
"io.portainer.job.endpoint": strconv.Itoa(int(endpoint.ID)),
|
||||
},
|
||||
Cmd: strslice.StrSlice([]string{"sh", "/tmp/script.sh"}),
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
Binds: []string{"/:/host", "/etc:/etc:ro", "/usr:/usr:ro", "/run:/run:ro", "/sbin:/sbin:ro", "/var:/var:ro"},
|
||||
NetworkMode: "host",
|
||||
Privileged: true,
|
||||
}
|
||||
|
||||
networkConfig := &network.NetworkingConfig{}
|
||||
|
||||
body, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkConfig, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copyOptions := types.CopyToContainerOptions{}
|
||||
err = cli.CopyToContainer(context.Background(), body.ID, "/tmp", bytes.NewReader(buffer), copyOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
startOptions := types.ContainerStartOptions{}
|
||||
err = cli.ContainerStart(context.Background(), body.ID, startOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pullImage(cli *client.Client, image string) error {
|
||||
imageReadCloser, err := cli.ImagePull(context.Background(), image, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer imageReadCloser.Close()
|
||||
|
||||
_, err = io.Copy(ioutil.Discard, imageReadCloser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue