Skip to content

Commit

Permalink
Merge pull request #7 from henderjm/master
Browse files Browse the repository at this point in the history
Add Jumpbox support provided by BBL
  • Loading branch information
rkoster authored Mar 26, 2018
2 parents b3a6109 + 95bb2b4 commit 1dcad3f
Show file tree
Hide file tree
Showing 38 changed files with 226 additions and 104 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM concourse/buildroot:base
MAINTAINER https://github.com/starkandwayne/bosh2-errand-resource
MAINTAINER https://github.com/cloudfoundry-community/bosh2-errand-resource

ADD check /opt/resource/check
ADD in /opt/resource/in
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A resource that will run an errand using the [BOSH CLI v2](https://bosh.io/docs/

## Differences from original BOSH Deployment Resource

The original [BOSH Errand Resource](https://github.com/starkandwayne/bosh-errand-resource)
The original [BOSH Errand Resource](https://github.com/cloudfoundry-community/bosh-errand-resource)
uses the Ruby CLI and does not support newer BOSH features (for example UAA auth).

### Breaking Changes
Expand All @@ -21,7 +21,7 @@ resource_types:
- name: bosh-errand
type: docker-image
source:
repository: starkandwayne/bosh2-errand-resource
repository: cloudfoundry-community/bosh2-errand-resource
```

## Source Configuration
Expand All @@ -33,6 +33,10 @@ resource_types:
* `client_secret`: *Required.* The password or UAA client secret for the BOSH director.
* `ca_cert`: *Optional.* CA certificate used to validate SSL connections to Director and UAA. If omitted, the director's
certificate must be already trusted.
* `jumpbox_url`: *Optional.* The URL, including port, of the jumpbox. If set, `jumpbox_ssh_key` must also be set. If omitted,
the BOSH director will be dialed directly.
* `jumpbox_ssh_key`: *Optional.* The private key of the jumpbox. If set, `jumpbox_url` must also be set.
* `jumpbox_username`: *Optional.* The username for the jumpbox. If not set, will default to `jumpbox`.

### Example

Expand Down
2 changes: 1 addition & 1 deletion bosh/boshfakes/fake_director.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package boshfakes
import (
"sync"

"github.com/starkandwayne/bosh2-errand-resource/bosh"
"github.com/cloudfoundry-community/bosh2-errand-resource/bosh"
)

type FakeDirector struct {
Expand Down
65 changes: 55 additions & 10 deletions bosh/boshfakes/fake_runner.go

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

75 changes: 58 additions & 17 deletions bosh/cli_coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package bosh

import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/starkandwayne/bosh2-errand-resource/concourse"
"github.com/cloudfoundry-community/bosh2-errand-resource/concourse"

boshcmd "github.com/cloudfoundry/bosh-cli/cmd"
cmdconf "github.com/cloudfoundry/bosh-cli/cmd/config"
Expand All @@ -15,19 +18,26 @@ import (
goflags "github.com/jessevdk/go-flags"
)

type Proxy interface {
Start(string, string, string) error
Addr() (string, error)
}

type CLICoordinator struct {
source concourse.Source
out io.Writer
proxy Proxy
}

func NewCLICoordinator(source concourse.Source, out io.Writer) CLICoordinator {
func NewCLICoordinator(source concourse.Source, out io.Writer, proxy Proxy) CLICoordinator {
return CLICoordinator{
source: source,
out: out,
proxy: proxy,
}
}

func (c CLICoordinator) GlobalOpts() boshcmd.BoshOpts {
func (c CLICoordinator) GlobalOpts(proxyAddr string) boshcmd.BoshOpts {
globalOpts := &boshcmd.BoshOpts{
NonInteractiveOpt: true,
CACertOpt: boshcmd.CACertArg{Content: c.source.CACert},
Expand All @@ -37,39 +47,70 @@ func (c CLICoordinator) GlobalOpts() boshcmd.BoshOpts {
DeploymentOpt: c.source.Deployment,
}

if proxyAddr != "" {
proxyAddr = fmt.Sprintf("socks5://%s", proxyAddr)
os.Setenv("BOSH_ALL_PROXY", proxyAddr)
globalOpts.SSH.GatewayFlags.SOCKS5Proxy = proxyAddr
globalOpts.SCP.GatewayFlags.SOCKS5Proxy = proxyAddr
globalOpts.Logs.GatewayFlags.SOCKS5Proxy = proxyAddr
}

setDefaults(globalOpts)

return *globalOpts
}

func (c CLICoordinator) StreamingBasicDeps() boshcmd.BasicDeps {
func (c CLICoordinator) BasicDeps(writer io.Writer) boshcmd.BasicDeps {
logger := nullLogger()

parentUI := boshui.NewPaddingUI(boshui.NewWriterUI(c.out, c.out, logger))

ui := boshui.NewWrappingConfUI(parentUI, logger)
return boshcmd.NewBasicDeps(ui, logger)
}

func (c CLICoordinator) CapturedBasicDeps() boshcmd.BasicDeps {
byteWriter := bytes.NewBufferString("")
logger := nullLogger()

parentUI := boshui.NewNonTTYUI(boshui.NewWriterUI(byteWriter, c.out, logger))
if writer == nil {
writer = c.out
}
parentUI := boshui.NewPaddingUI(boshui.NewWriterUI(writer, writer, logger))

ui := boshui.NewWrappingConfUI(parentUI, logger)
return boshcmd.NewBasicDeps(ui, logger)
}

func (c CLICoordinator) Director() (boshdir.Director, error) {
globalOpts := c.GlobalOpts()
deps := c.CapturedBasicDeps()
addr, err := c.StartProxy()
if err != nil {
return nil, fmt.Errorf("start proxy: %s", err) // untested
}
globalOpts := c.GlobalOpts(addr)
deps := c.BasicDeps(bytes.NewBufferString(""))
config, _ := cmdconf.NewFSConfigFromPath(globalOpts.ConfigPathOpt, deps.FS)
session := boshcmd.NewSessionFromOpts(globalOpts, config, deps.UI, true, true, deps.FS, deps.Logger)

return session.Director()
}

func (c CLICoordinator) StartProxy() (string, error) {
if c.source.JumpboxSSHKey == "" && c.source.JumpboxURL == "" {
return "", nil
}

if c.source.JumpboxSSHKey != "" && c.source.JumpboxURL != "" {
addr, err := c.proxy.Addr()
if err == nil {
return addr, nil
}

err = c.proxy.Start(c.source.JumpboxUsername, c.source.JumpboxSSHKey, c.source.JumpboxURL)
if err != nil {
panic(err)
}

addr, err = c.proxy.Addr()
if err != nil {
panic(err)
}
return addr, nil
}

return "", errors.New("Jumpbox URL and Jumpbox SSH Key are both required to use a jumpbox")
}

func nullLogger() boshlog.Logger {
return boshlog.NewWriterLogger(boshlog.LevelInfo, ioutil.Discard, ioutil.Discard)
}
Expand Down
23 changes: 17 additions & 6 deletions bosh/command_runner.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package bosh

import (
"fmt"

"io"

boshcmd "github.com/cloudfoundry/bosh-cli/cmd"
)

type Runner interface {
Execute(commandOpts interface{}) error
ExecuteWithDefaultOverride(commandOpts interface{}, override func(interface{}) (interface{}, error)) error
ExecuteWithDefaultOverride(commandOpts interface{}, override func(interface{}) (interface{}, error), writer io.Writer) error
}

type CommandRunner struct {
Expand All @@ -20,15 +24,22 @@ func NewCommandRunner(cliCoordinator CLICoordinator) CommandRunner {
}

func (c CommandRunner) Execute(commandOpts interface{}) error {
return c.ExecuteWithDefaultOverride(commandOpts, func(opts interface{}) (interface{}, error) { return opts, nil })
return c.ExecuteWithDefaultOverride(commandOpts, func(opts interface{}) (interface{}, error) { return opts, nil }, nil)
}

func (c CommandRunner) ExecuteWithDefaultOverride(commandOpts interface{}, override func(interface{}) (interface{}, error)) error {
deps := c.cliCoordinator.StreamingBasicDeps()
globalOpts := c.cliCoordinator.GlobalOpts()
func (c CommandRunner) ExecuteWithDefaultOverride(commandOpts interface{}, override func(interface{}) (interface{}, error), writer io.Writer) error {
deps := c.cliCoordinator.BasicDeps(writer)

addr, err := c.cliCoordinator.StartProxy()
if err != nil {
return fmt.Errorf("start proxy: %s", err)
}

globalOpts := c.cliCoordinator.GlobalOpts(addr)

setDefaults(commandOpts)

commandOpts, err := override(commandOpts)
commandOpts, err = override(commandOpts)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion bosh/deployment_manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/starkandwayne/bosh2-errand-resource/bosh"
"github.com/cloudfoundry-community/bosh2-errand-resource/bosh"
)

var _ = Describe("DeploymentManifest", func() {
Expand Down
4 changes: 2 additions & 2 deletions bosh/director.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"io/ioutil"

"github.com/starkandwayne/bosh2-errand-resource/concourse"
"github.com/cloudfoundry-community/bosh2-errand-resource/concourse"

boshcmd "github.com/cloudfoundry/bosh-cli/cmd"
boshdir "github.com/cloudfoundry/bosh-cli/director"
Expand Down Expand Up @@ -155,7 +155,7 @@ func (d BoshDirector) ExportReleases(targetDirectory string, releases []string)
err = d.commandRunner.ExecuteWithDefaultOverride(&boshcmd.ExportReleaseOpts{
Args: boshcmd.ExportReleaseArgs{ReleaseSlug: releaseSlug, OSVersionSlug: osVersionSlug},
Directory: directory,
}, directoryFixFunction)
}, directoryFixFunction, nil)
if err != nil {
return fmt.Errorf("could not export release %s: %s", deploymentRelease.Name(), err)
}
Expand Down
Loading

0 comments on commit 1dcad3f

Please sign in to comment.