mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-29 13:49:28 +08:00

* Use normalizer as stream source Renamed 'writer' service to 'normalizer' and dropped Cassandra facilities from it. Extracted the common dependencies to 'mainflux' package for easier sharing. Fixed the API docs and unified environment variables. Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Use docker build arguments to specify build Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Remove cassandra libraries Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Update go-kit version to 0.6.0 Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Fix manager configuration Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Refactor docker-compose Merged individual compose files and dropped external links. Remove CoAP container since it is not referenced from NginX config at the moment. Update port mapping in compose and nginx.conf. Dropped bin scripts. Updated service documentation. Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Drop content-type check Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Implement users data access layer in PostgreSQL Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Bump version to 0.1.0 Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Use go-kit logger everywhere (except CoAP) Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Improve factory methods naming Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Implement clients data access layer on PostgreSQL Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Make tests stateless All tests are refactored to use map-based table-driven tests. No cross-tests dependencies is present anymore. Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Remove gitignore Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Fix nginx proxying Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Mark client-user FK explicit Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Update API documentation Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Update channel model Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Add channel PostgreSQL repository tests Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Implement PostgreSQL channels DAO Replaced update queries with raw SQL. Explicitly defined M2M table due to difficulties of ensuring the referential integrity through GORM. Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Expose connection endpoints Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Fix swagger docs and remove DB logging Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Fix nested query remarks Signed-off-by: Dejan Mijic <dejan@mainflux.com> * Add unique indices Signed-off-by: Dejan Mijic <dejan@mainflux.com>
215 lines
8.0 KiB
Go
215 lines
8.0 KiB
Go
// Copyright 2014 go-dockerclient authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package docker
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
// Exec is the type representing a `docker exec` instance and containing the
|
|
// instance ID
|
|
type Exec struct {
|
|
ID string `json:"Id,omitempty" yaml:"Id,omitempty"`
|
|
}
|
|
|
|
// CreateExecOptions specify parameters to the CreateExecContainer function.
|
|
//
|
|
// See https://goo.gl/60TeBP for more details
|
|
type CreateExecOptions struct {
|
|
AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty" toml:"AttachStdin,omitempty"`
|
|
AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty" toml:"AttachStdout,omitempty"`
|
|
AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty" toml:"AttachStderr,omitempty"`
|
|
Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`
|
|
Env []string `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
|
|
Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty" toml:"Cmd,omitempty"`
|
|
Container string `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"`
|
|
User string `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
|
|
Context context.Context `json:"-"`
|
|
Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"`
|
|
}
|
|
|
|
// CreateExec sets up an exec instance in a running container `id`, returning the exec
|
|
// instance, or an error in case of failure.
|
|
//
|
|
// See https://goo.gl/60TeBP for more details
|
|
func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) {
|
|
if len(opts.Env) > 0 && c.serverAPIVersion.LessThan(apiVersion125) {
|
|
return nil, errors.New("exec configuration Env is only supported in API#1.25 and above")
|
|
}
|
|
path := fmt.Sprintf("/containers/%s/exec", opts.Container)
|
|
resp, err := c.do("POST", path, doOptions{data: opts, context: opts.Context})
|
|
if err != nil {
|
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
|
return nil, &NoSuchContainer{ID: opts.Container}
|
|
}
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
var exec Exec
|
|
if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &exec, nil
|
|
}
|
|
|
|
// StartExecOptions specify parameters to the StartExecContainer function.
|
|
//
|
|
// See https://goo.gl/1EeDWi for more details
|
|
type StartExecOptions struct {
|
|
InputStream io.Reader `qs:"-"`
|
|
OutputStream io.Writer `qs:"-"`
|
|
ErrorStream io.Writer `qs:"-"`
|
|
|
|
Detach bool `json:"Detach,omitempty" yaml:"Detach,omitempty" toml:"Detach,omitempty"`
|
|
Tty bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`
|
|
|
|
// Use raw terminal? Usually true when the container contains a TTY.
|
|
RawTerminal bool `qs:"-"`
|
|
|
|
// If set, after a successful connect, a sentinel will be sent and then the
|
|
// client will block on receive before continuing.
|
|
//
|
|
// It must be an unbuffered channel. Using a buffered channel can lead
|
|
// to unexpected behavior.
|
|
Success chan struct{} `json:"-"`
|
|
|
|
Context context.Context `json:"-"`
|
|
}
|
|
|
|
// StartExec starts a previously set up exec instance id. If opts.Detach is
|
|
// true, it returns after starting the exec command. Otherwise, it sets up an
|
|
// interactive session with the exec command.
|
|
//
|
|
// See https://goo.gl/1EeDWi for more details
|
|
func (c *Client) StartExec(id string, opts StartExecOptions) error {
|
|
cw, err := c.StartExecNonBlocking(id, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if cw != nil {
|
|
return cw.Wait()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StartExecNonBlocking starts a previously set up exec instance id. If opts.Detach is
|
|
// true, it returns after starting the exec command. Otherwise, it sets up an
|
|
// interactive session with the exec command.
|
|
//
|
|
// See https://goo.gl/1EeDWi for more details
|
|
func (c *Client) StartExecNonBlocking(id string, opts StartExecOptions) (CloseWaiter, error) {
|
|
if id == "" {
|
|
return nil, &NoSuchExec{ID: id}
|
|
}
|
|
|
|
path := fmt.Sprintf("/exec/%s/start", id)
|
|
|
|
if opts.Detach {
|
|
resp, err := c.do("POST", path, doOptions{data: opts, context: opts.Context})
|
|
if err != nil {
|
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
|
return nil, &NoSuchExec{ID: id}
|
|
}
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
return nil, nil
|
|
}
|
|
|
|
return c.hijack("POST", path, hijackOptions{
|
|
success: opts.Success,
|
|
setRawTerminal: opts.RawTerminal,
|
|
in: opts.InputStream,
|
|
stdout: opts.OutputStream,
|
|
stderr: opts.ErrorStream,
|
|
data: opts,
|
|
})
|
|
}
|
|
|
|
// ResizeExecTTY resizes the tty session used by the exec command id. This API
|
|
// is valid only if Tty was specified as part of creating and starting the exec
|
|
// command.
|
|
//
|
|
// See https://goo.gl/Mo5bxx for more details
|
|
func (c *Client) ResizeExecTTY(id string, height, width int) error {
|
|
params := make(url.Values)
|
|
params.Set("h", strconv.Itoa(height))
|
|
params.Set("w", strconv.Itoa(width))
|
|
|
|
path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode())
|
|
resp, err := c.do("POST", path, doOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp.Body.Close()
|
|
return nil
|
|
}
|
|
|
|
// ExecProcessConfig is a type describing the command associated to a Exec
|
|
// instance. It's used in the ExecInspect type.
|
|
type ExecProcessConfig struct {
|
|
User string `json:"user,omitempty" yaml:"user,omitempty" toml:"user,omitempty"`
|
|
Privileged bool `json:"privileged,omitempty" yaml:"privileged,omitempty" toml:"privileged,omitempty"`
|
|
Tty bool `json:"tty,omitempty" yaml:"tty,omitempty" toml:"tty,omitempty"`
|
|
EntryPoint string `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty" toml:"entrypoint,omitempty"`
|
|
Arguments []string `json:"arguments,omitempty" yaml:"arguments,omitempty" toml:"arguments,omitempty"`
|
|
}
|
|
|
|
// ExecInspect is a type with details about a exec instance, including the
|
|
// exit code if the command has finished running. It's returned by a api
|
|
// call to /exec/(id)/json
|
|
//
|
|
// See https://goo.gl/ctMUiW for more details
|
|
type ExecInspect struct {
|
|
ID string `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"`
|
|
ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
|
|
Running bool `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"`
|
|
OpenStdin bool `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty" toml:"OpenStdin,omitempty"`
|
|
OpenStderr bool `json:"OpenStderr,omitempty" yaml:"OpenStderr,omitempty" toml:"OpenStderr,omitempty"`
|
|
OpenStdout bool `json:"OpenStdout,omitempty" yaml:"OpenStdout,omitempty" toml:"OpenStdout,omitempty"`
|
|
ProcessConfig ExecProcessConfig `json:"ProcessConfig,omitempty" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"`
|
|
ContainerID string `json:"ContainerID,omitempty" yaml:"ContainerID,omitempty" toml:"ContainerID,omitempty"`
|
|
DetachKeys string `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
|
|
CanRemove bool `json:"CanRemove,omitempty" yaml:"CanRemove,omitempty" toml:"CanRemove,omitempty"`
|
|
}
|
|
|
|
// InspectExec returns low-level information about the exec command id.
|
|
//
|
|
// See https://goo.gl/ctMUiW for more details
|
|
func (c *Client) InspectExec(id string) (*ExecInspect, error) {
|
|
path := fmt.Sprintf("/exec/%s/json", id)
|
|
resp, err := c.do("GET", path, doOptions{})
|
|
if err != nil {
|
|
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
|
return nil, &NoSuchExec{ID: id}
|
|
}
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
var exec ExecInspect
|
|
if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
|
|
return nil, err
|
|
}
|
|
return &exec, nil
|
|
}
|
|
|
|
// NoSuchExec is the error returned when a given exec instance does not exist.
|
|
type NoSuchExec struct {
|
|
ID string
|
|
}
|
|
|
|
func (err *NoSuchExec) Error() string {
|
|
return "No such exec instance: " + err.ID
|
|
}
|