// TODO(random-liu): Add unit test for exec and attach functions, just like what go-dockerclient did. func (d *kubeDockerClient) CreateExec(id string, opts dockertypes.ExecConfig) (*dockertypes.ContainerExecCreateResponse, error) { opts.Container = id resp, err := d.client.ContainerExecCreate(getDefaultContext(), opts) if err != nil { return nil, err } return &resp, nil }
func (s *Swarm) Exec(cmd []string, containName string) (types.HijackedResponse, error) { var err error defer func() { if err != nil { log.WithFields(log.Fields{ "cmd": cmd, "ContainName": containName, "err": err.Error(), }).Error("swarm exec error") } }() timeEnd := time.Now().Add(s.config.SwarmRetryTimeoutAll) defaultHeaders := map[string]string{"User-Agent": s.config.SwarmUserAgent} // for set client.Timeout do what engine-api do start // transport = defaultTransport(proto, addr) transport := new(http.Transport) sockets.ConfigureTransport(transport, "tcp", s.host) // for set client.Timeout do what engine-api do end c := &http.Client{ Timeout: s.config.SwarmRetryTimeout, Transport: transport, } // get last swarm host when connect error and retry once bRegetSwarmHost := false for i := 1; i <= s.config.SwarmRetryTimes; i++ { if timeEnd.Before(time.Now()) { return types.HijackedResponse{}, errors.New(fmt.Sprintf("time out after %+v\n", s.config.SwarmRetryTimeoutAll)) } cli, err := client.NewClient("tcp://"+s.host, s.ApiVersion, c, defaultHeaders) if err != nil { log.WithFields(log.Fields{ "cmd": cmd, "ContainName": containName, "RetryTimes": i, "err": err.Error(), }).Error("swarm NewClient error") if !bRegetSwarmHost && s.consul != nil { log.Info("try to get swarm host from consul once again") bRegetSwarmHost = true swarmHost, err := s.consul.GetVal(s.config.SwarmHostKey) if err != nil { log.WithFields(log.Fields{ "err": err.Error(), }).Error("consul connect error") time.Sleep(s.config.SwarmRetryInterval) } else if swarmHost == "" { log.WithFields(log.Fields{ "key": s.config.SwarmHostKey, "err": err.Error(), }).Error("get empty SwarmHost from consul") time.Sleep(s.config.SwarmRetryInterval) } else { log.WithFields(log.Fields{ "OldSwarmHost": s.host, "NewSwarmHost": swarmHost, }).Info("swarm host updated from consul") s.host = swarmHost // retry once cli, err = client.NewClient("tcp://"+s.host, s.ApiVersion, c, defaultHeaders) if err != nil { log.WithFields(log.Fields{ "err": err.Error(), }).Error("swarm reconnect error") } } } else { time.Sleep(s.config.SwarmRetryInterval) continue } } execConfig := types.ExecConfig{ Tty: true, Detach: false, AttachStdin: true, AttachStderr: true, AttachStdout: true, } //execConfig.Container = containName execConfig.Cmd = cmd creres, err := cli.ContainerExecCreate(context.Background(), containName, execConfig) if err != nil { log.WithFields(log.Fields{ "cmd": cmd, "ContainName": containName, "RetryTimes": i, "err": err.Error(), }).Error("swarm ContainerExecCreate error") time.Sleep(s.config.SwarmRetryInterval) continue } res, err := cli.ContainerExecAttach(context.Background(), creres.ID, execConfig) if err != nil { log.WithFields(log.Fields{ "cmd": cmd, "ContainName": containName, "RetryTimes": i, "err": err.Error(), }).Error("swarm ContainerExecAttach error") time.Sleep(s.config.SwarmRetryInterval) continue } return res, nil } return types.HijackedResponse{}, errors.New(fmt.Sprintf("swarm exec cmd:%+v, containName:%s, retry %d times fail\n", cmd, containName, s.config.SwarmRetryTimes)) }