Skip to content

Commit

Permalink
Add Jumpbox support provided by BBL
Browse files Browse the repository at this point in the history
Newer versions of BoshBootLoader create directors private to the world
and the only way to connect to them is through a provided Jumpbox

* Rename package names to reflect repository. This is very confusing
having references to old repository name.
* Add Jumpbox url, ssh key and username to source configuration
* Update dependency calls where function definitions have changed
* Update README
  • Loading branch information
henderjm committed Mar 6, 2018
1 parent b3a6109 commit 95bb2b4
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 95bb2b4

Please sign in to comment.