コード例 #1
0
ファイル: server.go プロジェクト: xoebus/checkin
func (s *Server) forwardRequest(w http.ResponseWriter, r *http.Request, host string, route string, pipeID string) (*http.Response, error) {
	generator := rata.NewRequestGenerator(host, atc.Routes)

	req, err := generator.CreateRequest(
		route,
		rata.Params{"pipe_id": pipeID},
		r.Body,
	)

	if err != nil {
		return nil, err
	}

	req.Header = r.Header

	client := &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives: true,
		},
	}

	response, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	return response, nil
}
コード例 #2
0
ファイル: client.go プロジェクト: cloudfoundry/bbs
func newClient(url string) *client {
	return &client{
		httpClient:          cfhttp.NewClient(),
		streamingHTTPClient: cfhttp.NewStreamingClient(),
		reqGen:              rata.NewRequestGenerator(url, Routes),
	}
}
コード例 #3
0
ファイル: client.go プロジェクト: Gerg/bbs
func (c *client) StopLRPInstance(
	cellURL string,
	key models.ActualLRPKey,
	instanceKey models.ActualLRPInstanceKey,
) error {
	reqGen := rata.NewRequestGenerator(cellURL, Routes)

	req, err := reqGen.CreateRequest(StopLRPInstanceRoute, stopParamsFromLRP(key, instanceKey), nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("http error: status code %d (%s)", resp.StatusCode, http.StatusText(resp.StatusCode))
	}

	return nil
}
コード例 #4
0
ファイル: set_pipeline.go プロジェクト: mmb/fly
func (command *SetPipelineCommand) Execute(args []string) error {
	configPath := command.Config
	templateVariablesFiles := command.VarsFrom
	pipelineName := command.Pipeline

	templateVariables := template.Variables{}
	for _, v := range command.Var {
		templateVariables[v.Name] = v.Value
	}

	connection, err := rc.TargetConnection(Fly.Target)
	if err != nil {
		log.Fatalln(err)
		return nil
	}
	client := concourse.NewClient(connection)

	webRequestGenerator := rata.NewRequestGenerator(connection.URL(), web.Routes)

	atcConfig := ATCConfig{
		pipelineName:        pipelineName,
		webRequestGenerator: webRequestGenerator,
		client:              client,
	}

	atcConfig.Set(configPath, templateVariables, templateVariablesFiles)
	return nil
}
コード例 #5
0
ファイル: client.go プロジェクト: cfibmers/auctioneer
func (c *auctioneerClient) RequestTaskAuctions(tasks []*TaskStartRequest) error {
	reqGen := rata.NewRequestGenerator(c.url, Routes)

	payload, err := json.Marshal(tasks)
	if err != nil {
		return err
	}

	req, err := reqGen.CreateRequest(CreateTaskAuctionsRoute, rata.Params{}, bytes.NewBuffer(payload))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("http error: status code %d (%s)", resp.StatusCode, http.StatusText(resp.StatusCode))
	}

	return nil
}
コード例 #6
0
ファイル: set_pipeline.go プロジェクト: ArthurHlt/fly
func (command *SetPipelineCommand) Execute(args []string) error {
	configPath := command.Config
	templateVariablesFiles := command.VarsFrom
	pipelineName := command.Pipeline

	templateVariables := template.Variables{}
	for _, v := range command.Var {
		templateVariables[v.Name] = v.Value
	}

	client, err := rc.TargetClient(Fly.Target)
	if err != nil {
		return err
	}
	err = rc.ValidateClient(client, Fly.Target)
	if err != nil {
		return err
	}

	webRequestGenerator := rata.NewRequestGenerator(client.URL(), web.Routes)

	atcConfig := setpipelinehelpers.ATCConfig{
		PipelineName:        pipelineName,
		WebRequestGenerator: webRequestGenerator,
		Client:              client,
		SkipInteraction:     command.SkipInteractive,
	}

	return atcConfig.Set(configPath, templateVariables, templateVariablesFiles)
}
コード例 #7
0
ファイル: client.go プロジェクト: jianhuiz/rep
func NewClient(httpClient *http.Client, address string) Client {
	return &client{
		client:           httpClient,
		address:          address,
		requestGenerator: rata.NewRequestGenerator(address, Routes),
	}
}
コード例 #8
0
ファイル: create.go プロジェクト: xoebus/checkin
func (s *Server) CreatePipe(w http.ResponseWriter, r *http.Request) {
	logger := s.logger.Session("create-pipe")
	guid, err := uuid.NewV4()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	err = s.db.CreatePipe(guid.String(), s.url)
	if err != nil {
		logger.Error("failed-to-create-pipe", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	pr, pw := io.Pipe()

	pipeID := guid.String()

	reqGen := rata.NewRequestGenerator(s.externalURL, atc.Routes)

	readReq, err := reqGen.CreateRequest(atc.ReadPipe, rata.Params{
		"pipe_id": pipeID,
	}, nil)
	if err != nil {
		logger.Error("failed-to-create-pipe", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	writeReq, err := reqGen.CreateRequest(atc.WritePipe, rata.Params{
		"pipe_id": pipeID,
	}, nil)
	if err != nil {
		logger.Error("failed-to-create-pipe", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	pipeResource := atc.Pipe{
		ID:       pipeID,
		ReadURL:  readReq.URL.String(),
		WriteURL: writeReq.URL.String(),
	}

	pipe := pipe{
		resource: pipeResource,

		read:  pr,
		write: pw,
	}

	s.pipesL.Lock()
	s.pipes[pipeResource.ID] = pipe
	s.pipesL.Unlock()

	w.WriteHeader(http.StatusCreated)

	json.NewEncoder(w).Encode(pipeResource)
}
コード例 #9
0
ファイル: execute.go プロジェクト: simonjjones/fly
func newAtcRequester(target string, insecure bool) *atcRequester {
	tlsClientConfig := &tls.Config{InsecureSkipVerify: insecure}

	return &atcRequester{
		rata.NewRequestGenerator(target, atc.Routes),
		&http.Client{Transport: &http.Transport{TLSClientConfig: tlsClientConfig}},
	}
}
コード例 #10
0
ファイル: hijack.go プロジェクト: simonjjones/fly
func Hijack(c *cli.Context) {
	target := returnTarget(c.GlobalString("target"))
	insecure := c.GlobalBool("insecure")

	stepType := c.String("step-type")
	stepName := c.String("step-name")
	check := c.String("check")
	pipelineName := c.String("pipeline")
	jobName := c.String("job")
	buildName := c.String("build")

	path, args := remoteCommand(c.Args())
	privileged := true

	fingerprint := containerFingerprint{
		pipelineName: pipelineName,
		jobName:      jobName,
		buildName:    buildName,
		stepName:     stepName,
		stepType:     stepType,
		checkName:    check,
	}

	reqGenerator := rata.NewRequestGenerator(target, atc.Routes)
	tlsConfig := &tls.Config{InsecureSkipVerify: insecure}
	transport := &http.Transport{
		TLSClientConfig: tlsConfig,
	}
	client := &http.Client{Transport: transport}

	reqValues := locateContainer(client, reqGenerator, fingerprint)

	var ttySpec *atc.HijackTTYSpec
	rows, cols, err := pty.Getsize(os.Stdin)
	if err == nil {
		ttySpec = &atc.HijackTTYSpec{
			WindowSize: atc.HijackWindowSize{
				Columns: cols,
				Rows:    rows,
			},
		}
	}

	spec := atc.HijackProcessSpec{
		Path: path,
		Args: args,
		Env:  []string{"TERM=" + os.Getenv("TERM")},
		User: "******",

		Privileged: privileged,
		TTY:        ttySpec,
	}

	hijackReq := constructRequest(reqGenerator, spec, reqValues)
	hijackResult := performHijack(hijackReq, tlsConfig)
	os.Exit(hijackResult)
}
コード例 #11
0
ファイル: client.go プロジェクト: idouba/gorouter
func NewClient(url string) Client {
	return &client{
		httpClient:          cf_http.NewClient(),
		streamingHTTPClient: cf_http.NewStreamingClient(),

		tokenMutex: &sync.RWMutex{},

		reqGen: rata.NewRequestGenerator(url, Routes),
	}
}
コード例 #12
0
func NewHijackStreamerWithDialer(dialFunc DialerFunc) HijackStreamer {
	return &hijackable{
		req:    rata.NewRequestGenerator("http://api", routes.Routes),
		dialer: dialFunc,
		noKeepaliveClient: &http.Client{
			Transport: &http.Transport{
				Dial:              dialFunc,
				DisableKeepAlives: true,
			},
		},
	}
}
コード例 #13
0
ファイル: client.go プロジェクト: Reejoshi/cli
func NewClient(ccEndpoint, uaaEndpoint, accessToken, refreshToken string) Client {
	tokenRefresher := NewTokenRefresher(uaaEndpoint)
	baseFetcher := NewBaseFetcher(tokenRefresher, refreshToken)
	return &client{
		ccEndpoint:   ccEndpoint,
		accessToken:  accessToken,
		refreshToken: refreshToken,

		ccRequestGenerator: rata.NewRequestGenerator(ccEndpoint, routing.CCRoutes),
		httpClient:         &http.Client{},
		baseFetcher:        baseFetcher,
	}
}
コード例 #14
0
func NewConnection(APIURL string, routes rata.Routes, skipSSLValidation bool) *CloudControllerConnection {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: skipSSLValidation,
		},
	}

	return &CloudControllerConnection{
		HTTPClient: &http.Client{Transport: tr},

		URL:              strings.TrimRight(APIURL, "/"),
		requestGenerator: rata.NewRequestGenerator(APIURL, routes),
	}
}
コード例 #15
0
ファイル: connection.go プロジェクト: xoebus/checkin
func NewConnection(apiURL string, httpClient *http.Client) Connection {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	apiURL = strings.TrimRight(apiURL, "/")

	return &connection{
		url:        apiURL,
		httpClient: httpClient,

		requestGenerator: rata.NewRequestGenerator(apiURL, atc.Routes),
	}
}
コード例 #16
0
ファイル: connection_hijacker.go プロジェクト: savaki/garden
func NewHijackStreamer(network, address string) HijackStreamer {
	dialer := func(string, string) (net.Conn, error) {
		return net.DialTimeout(network, address, time.Second)
	}

	return &hijackable{
		req:    rata.NewRequestGenerator("http://api", routes.Routes),
		dialer: dialer,
		noKeepaliveClient: &http.Client{
			Transport: &http.Transport{
				Dial:              dialer,
				DisableKeepAlives: true,
			},
		},
	}
}
コード例 #17
0
ファイル: job.go プロジェクト: utako/atc
func Job(dbJob db.SavedJob, job atc.JobConfig, groups atc.GroupConfigs, finishedBuild, nextBuild *db.Build) atc.Job {
	generator := rata.NewRequestGenerator("", routes.Routes)

	req, err := generator.CreateRequest(
		routes.GetJob,
		rata.Params{"job": job.Name, "pipeline_name": dbJob.PipelineName},
		nil,
	)
	if err != nil {
		panic("failed to generate url: " + err.Error())
	}

	var presentedNextBuild, presentedFinishedBuild *atc.Build

	if nextBuild != nil {
		presented := Build(*nextBuild)
		presentedNextBuild = &presented
	}

	if finishedBuild != nil {
		presented := Build(*finishedBuild)
		presentedFinishedBuild = &presented
	}

	groupNames := []string{}
	for _, group := range groups {
		for _, name := range group.Jobs {
			if name == job.Name {
				groupNames = append(groupNames, group.Name)
			}
		}
	}

	return atc.Job{
		Name:          job.Name,
		URL:           req.URL.String(),
		Paused:        dbJob.Paused,
		FinishedBuild: presentedFinishedBuild,
		NextBuild:     presentedNextBuild,

		Inputs:  job.Inputs(),
		Outputs: job.Outputs(),

		Groups: groupNames,
	}
}
コード例 #18
0
func rataWrap(handler http.Handler, method, path string, params rata.Params) (http.Handler, *http.Request) {
	testRoutes := rata.Routes{
		{Name: "wicked_smat", Method: method, Path: path},
	}
	requestGenerator := rata.NewRequestGenerator("", testRoutes)
	testHandlers := rata.Handlers{
		"wicked_smat": handler,
	}

	router, err := rata.NewRouter(testRoutes, testHandlers)
	Expect(err).NotTo(HaveOccurred())

	request, err := requestGenerator.CreateRequest("wicked_smat", params, nil)
	Expect(err).NotTo(HaveOccurred())

	return router, request
}
コード例 #19
0
ファイル: lrp_instances.go プロジェクト: Gerg/inigo
func GetLRPInstances(tpsAddr string, guid string) []cc_messages.LRPInstance {
	tpsRequestGenerator := rata.NewRequestGenerator("http://"+tpsAddr, tps.Routes)

	getLRPs, err := tpsRequestGenerator.CreateRequest(
		tps.LRPStatus,
		rata.Params{"guid": guid},
		nil,
	)
	Expect(err).NotTo(HaveOccurred())

	response, err := http.DefaultClient.Do(getLRPs)
	Expect(err).NotTo(HaveOccurred())
	defer response.Body.Close()

	var instances []cc_messages.LRPInstance
	err = json.NewDecoder(response.Body).Decode(&instances)
	Expect(err).NotTo(HaveOccurred())

	return instances
}
コード例 #20
0
ファイル: connection.go プロジェクト: julz/garden-runc
func NewWithLogger(network, address string, log lager.Logger) Connection {
	dialer := func(string, string) (net.Conn, error) {
		return net.DialTimeout(network, address, time.Second)
	}

	return &connection{
		req: rata.NewRequestGenerator("http://api", routes.Routes),

		dialer: dialer,

		noKeepaliveClient: &http.Client{
			Transport: &http.Transport{
				Dial:              dialer,
				DisableKeepAlives: true,
			},
		},

		log: log,
	}
}
コード例 #21
0
ファイル: build.go プロジェクト: utako/atc
func Build(build db.Build) atc.Build {
	generator := rata.NewRequestGenerator("", routes.Routes)

	req, err := generator.CreateRequest(
		routes.GetBuild,
		rata.Params{"job": build.JobName, "build": build.Name, "pipeline_name": build.PipelineName},
		nil,
	)
	if err != nil {
		panic("failed to generate url: " + err.Error())
	}

	return atc.Build{
		ID:      build.ID,
		Name:    build.Name,
		Status:  string(build.Status),
		JobName: build.JobName,
		URL:     req.URL.String(),
	}
}
コード例 #22
0
ファイル: sync.go プロジェクト: simonjjones/fly
func Sync(c *cli.Context) {
	target := returnTarget(c.GlobalString("target"))
	insecure := c.GlobalBool("insecure")
	reqGenerator := rata.NewRequestGenerator(target, atc.Routes)

	request, err := reqGenerator.CreateRequest(
		atc.DownloadCLI, rata.Params{}, nil,
	)
	if err != nil {
		fmt.Printf("building request failed: %v\n", err)
		os.Exit(1)
	}

	request.URL.RawQuery = url.Values{
		"arch":     []string{runtime.GOARCH},
		"platform": []string{runtime.GOOS},
	}.Encode()

	tlsConfig := &tls.Config{InsecureSkipVerify: insecure}

	transport := &http.Transport{TLSClientConfig: tlsConfig}

	client := &http.Client{Transport: transport}

	updateCustom := &update.Update{HTTPClient: client}

	fmt.Printf("downloading fly from %s... ", request.URL.Host)

	err, errRecover := updateCustom.FromUrl(request.URL.String())
	if err != nil {
		fmt.Printf("update failed: %v\n", err)
		if errRecover != nil {
			fmt.Printf("failed to recover previous executable: %v!\n", errRecover)
			fmt.Printf("things are probably in a bad state on your machine now.\n")
		}

		return
	}

	fmt.Println("update successful!")
}
コード例 #23
0
ファイル: client.go プロジェクト: Gerg/bbs
func (c *client) CancelTask(cellURL string, taskGuid string) error {
	reqGen := rata.NewRequestGenerator(cellURL, Routes)

	req, err := reqGen.CreateRequest(CancelTaskRoute, rata.Params{"task_guid": taskGuid}, nil)
	if err != nil {
		return err
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("http error: status code %d (%s)", resp.StatusCode, http.StatusText(resp.StatusCode))
	}

	return nil
}
コード例 #24
0
ファイル: main.go プロジェクト: savaki/tsa
func main() {
	flag.Parse()

	logger := lager.NewLogger("tsa")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.DEBUG))

	if len(*forwardHost) == 0 {
		logger.Fatal("missing-flag", nil, lager.Data{"flag": "-forwardHost"})
	}

	atcEndpoint := rata.NewRequestGenerator(*atcAPIURL, atc.Routes)

	authorizedKeys, err := loadAuthorizedKeys(*authorizedKeysPath)
	if err != nil {
		logger.Fatal("failed-to-load-authorized-keys", err)
	}

	config, err := configureSSHServer(*hostKeyPath, authorizedKeys)
	if err != nil {
		logger.Fatal("failed-to-configure-ssh-server", err)
	}

	listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", *listenPort))
	if err != nil {
		logger.Fatal("failed-to-listen-for-connection", err)
	}

	logger.Info("listening")

	server := &registrarSSHServer{
		logger:            logger,
		heartbeatInterval: *heartbeatInterval,
		atcEndpoint:       atcEndpoint,
		forwardHost:       *forwardHost,
		config:            config,
		httpClient:        http.DefaultClient,
	}

	server.Serve(listener)
}
コード例 #25
0
ファイル: configure.go プロジェクト: simonjjones/fly
func Configure(c *cli.Context) {
	var paused PipelineAction

	target := returnTarget(c.GlobalString("target"))
	insecure := c.GlobalBool("insecure")
	configPath := c.String("config")
	asJSON := c.Bool("json")
	templateVariables := c.StringSlice("var")
	templateVariablesFile := c.StringSlice("vars-from")
	pipelineName := c.Args().First()

	if c.IsSet("paused") {
		if c.Bool("paused") {
			paused = PausePipeline
		} else {
			paused = UnpausePipeline
		}
	} else {
		paused = DoNotChangePipeline
	}

	if pipelineName == "" {
		failf("please specify a pipeline name as an argument!")
	}

	apiRequester := newAtcRequester(target, insecure)
	webRequestGenerator := rata.NewRequestGenerator(target, atcroutes.Routes)

	atcConfig := ATCConfig{
		pipelineName:        pipelineName,
		apiRequester:        apiRequester,
		webRequestGenerator: webRequestGenerator,
	}

	if configPath == "" {
		atcConfig.Dump(asJSON)
	} else {
		atcConfig.Set(paused, configPath, templateVariables, templateVariablesFile)
	}
}
コード例 #26
0
ファイル: resource.go プロジェクト: ACPK/atc
func Resource(resource atc.ResourceConfig, groups atc.GroupConfigs, dbResource db.SavedResource, showCheckError bool) atc.Resource {
	generator := rata.NewRequestGenerator("", web.Routes)

	req, err := generator.CreateRequest(
		web.GetResource,
		rata.Params{"resource": resource.Name, "pipeline_name": dbResource.PipelineName},
		nil,
	)
	if err != nil {
		panic("failed to generate url: " + err.Error())
	}

	groupNames := []string{}
	for _, group := range groups {
		for _, name := range group.Resources {
			if name == resource.Name {
				groupNames = append(groupNames, group.Name)
			}
		}
	}

	var checkErrString string
	if dbResource.CheckError != nil && showCheckError {
		checkErrString = dbResource.CheckError.Error()
	}

	return atc.Resource{
		Name:   resource.Name,
		Type:   resource.Type,
		Groups: groupNames,
		URL:    req.URL.String(),

		Paused: dbResource.Paused,

		FailingToCheck: dbResource.FailingToCheck(),
		CheckError:     checkErrString,
	}
}
コード例 #27
0
ファイル: atc_requester.go プロジェクト: aemengo/fly
func NewAtcRequester(target string, httpClient *http.Client) *AtcRequester {
	return &AtcRequester{
		rata.NewRequestGenerator(target, atc.Routes),
		httpClient,
	}
}
コード例 #28
0
ファイル: job.go プロジェクト: ACPK/atc
func Job(dbJob db.SavedJob, job atc.JobConfig, groups atc.GroupConfigs, finishedBuild, nextBuild *db.Build) atc.Job {
	generator := rata.NewRequestGenerator("", web.Routes)

	req, err := generator.CreateRequest(
		web.GetJob,
		rata.Params{"job": job.Name, "pipeline_name": dbJob.PipelineName},
		nil,
	)
	if err != nil {
		panic("failed to generate url: " + err.Error())
	}

	var presentedNextBuild, presentedFinishedBuild *atc.Build

	if nextBuild != nil {
		presented := Build(*nextBuild)
		presentedNextBuild = &presented
	}

	if finishedBuild != nil {
		presented := Build(*finishedBuild)
		presentedFinishedBuild = &presented
	}

	groupNames := []string{}
	for _, group := range groups {
		for _, name := range group.Jobs {
			if name == job.Name {
				groupNames = append(groupNames, group.Name)
			}
		}
	}

	sanitizedInputs := []atc.JobInput{}
	for _, input := range config.JobInputs(job) {
		sanitizedInputs = append(sanitizedInputs, atc.JobInput{
			Name:     input.Name,
			Resource: input.Resource,
			Passed:   input.Passed,
			Trigger:  input.Trigger,
		})
	}

	sanitizedOutputs := []atc.JobOutput{}
	for _, output := range config.JobOutputs(job) {
		sanitizedOutputs = append(sanitizedOutputs, atc.JobOutput{
			Name:     output.Name,
			Resource: output.Resource,
		})
	}

	return atc.Job{
		Name:          job.Name,
		URL:           req.URL.String(),
		Paused:        dbJob.Paused,
		FinishedBuild: presentedFinishedBuild,
		NextBuild:     presentedNextBuild,

		Inputs:  sanitizedInputs,
		Outputs: sanitizedOutputs,

		Groups: groupNames,
	}
}
コード例 #29
0
ファイル: handlers_test.go プロジェクト: cfibmers/auctioneer
		responseRecorder = httptest.NewRecorder()

		sender = fake.NewFakeMetricSender()
		metrics.Initialize(sender, nil)

		handler = handlers.New(runner, logger)
	})

	Describe("Task Handler", func() {
		Context("with a valid task", func() {
			BeforeEach(func() {
				resource := rep.NewResource(1, 2, "rootfs", []string{})
				task := rep.NewTask("the-task-guid", "test", resource)

				tasks := []auctioneer.TaskStartRequest{auctioneer.TaskStartRequest{task}}
				reqGen := rata.NewRequestGenerator("http://localhost", auctioneer.Routes)

				payload, err := json.Marshal(tasks)
				Expect(err).NotTo(HaveOccurred())

				req, err := reqGen.CreateRequest(auctioneer.CreateTaskAuctionsRoute, rata.Params{}, bytes.NewBuffer(payload))
				Expect(err).NotTo(HaveOccurred())

				handler.ServeHTTP(responseRecorder, req)
			})

			It("responds with 202", func() {
				Expect(responseRecorder.Code).To(Equal(http.StatusAccepted))
			})

			It("logs with the correct session nesting", func() {
コード例 #30
0
ファイル: hijack.go プロジェクト: mmb/fly
func (command *HijackCommand) Execute(args []string) error {
	target, err := rc.SelectTarget(Fly.Target)
	if err != nil {
		log.Fatalln(err)
		return nil
	}

	containers := getContainerIDs(command)

	var id string
	if len(containers) == 0 {
		fmt.Fprintln(os.Stderr, "no containers matched your search parameters! they may have expired if your build hasn't recently finished")
		os.Exit(1)
	} else if len(containers) > 1 {
		var choices []interact.Choice
		for _, container := range containers {
			var infos []string
			if container.PipelineName != "" {
				infos = append(infos, fmt.Sprintf("pipeline: %s", container.PipelineName))
			}

			if container.BuildID != 0 {
				infos = append(infos, fmt.Sprintf("build id: %d", container.BuildID))
			}

			infos = append(infos, fmt.Sprintf("type: %s", container.Type))
			infos = append(infos, fmt.Sprintf("name: %s", container.Name))

			choices = append(choices, interact.Choice{
				Display: strings.Join(infos, ", "),
				Value:   container.ID,
			})
		}

		err = interact.NewInteraction("choose a container", choices...).Resolve(&id)
		if err == io.EOF {
			os.Exit(0)
		}

		if err != nil {
			return err
		}
	} else {
		id = containers[0].ID
	}

	path, args := remoteCommand(args)
	privileged := true

	reqGenerator := rata.NewRequestGenerator(target.API, atc.Routes)
	tlsConfig := &tls.Config{InsecureSkipVerify: target.Insecure}

	var ttySpec *atc.HijackTTYSpec
	rows, cols, err := pty.Getsize(os.Stdin)
	if err == nil {
		ttySpec = &atc.HijackTTYSpec{
			WindowSize: atc.HijackWindowSize{
				Columns: cols,
				Rows:    rows,
			},
		}
	}

	spec := atc.HijackProcessSpec{
		Path: path,
		Args: args,
		Env:  []string{"TERM=" + os.Getenv("TERM")},
		User: "******",

		Privileged: privileged,
		TTY:        ttySpec,
	}

	hijackReq := constructRequest(reqGenerator, spec, id, target.Token)
	hijackResult := performHijack(hijackReq, tlsConfig)
	os.Exit(hijackResult)

	return nil
}