-
Notifications
You must be signed in to change notification settings - Fork 3
allowing for http api to be used for fleet provider #1
base: master
Are you sure you want to change the base?
Changes from 5 commits
5c55564
738ebee
830c568
cd25c63
07b193a
f506ec6
67d9b0f
db56e45
7769f61
0d3546a
0941405
d370dfb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
bin/* | ||
terraform-provider-fleet | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,15 +6,31 @@ import ( | |
"net/url" | ||
"strings" | ||
"time" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/coreos/fleet/client" | ||
"github.com/coreos/fleet/pkg" | ||
"github.com/coreos/fleet/ssh" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/terraform" | ||
|
||
"github.com/coreos/fleet/version" | ||
"github.com/coreos/fleet/registry" | ||
|
||
etcd "github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/etcd/client" | ||
) | ||
|
||
const oldVersionWarning = `#################################################################### | ||
WARNING: fleetctl (%s) is older than the latest registered | ||
version of fleet found in the cluster (%s). You are strongly | ||
recommended to upgrade fleetctl to prevent incompatibility issues. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this message be clarified to make it more clear that it's not the |
||
#################################################################### | ||
` | ||
|
||
const defaultTimeout = time.Second*10 | ||
|
||
// retry wraps a function with retry logic. Only errors containing "timed out" | ||
// will be retried. (authentication errors and other stuff should fail | ||
// immediately) | ||
|
@@ -31,14 +47,67 @@ func retry(f func() (interface{}, error), maxRetries int) (interface{}, error) { | |
return result, err | ||
} | ||
|
||
// getAPI returns an API to Fleet. | ||
func getAPI(hostAddr string, maxRetries int) (client.API, error) { | ||
if hostAddr == "" { | ||
return nullAPI{}, nil | ||
func checkVersion(cReg registry.ClusterRegistry) (string, bool) { | ||
fv := version.SemVersion | ||
lv, err := cReg.LatestDaemonVersion() | ||
if err != nil { | ||
log.Fatal("error attempting to check latest fleet version in Registry: %v", err) | ||
} else if lv != nil && fv.LessThan(*lv) { | ||
return fmt.Sprintf(oldVersionWarning, fv.String(), lv.String()), false | ||
} | ||
return "", true | ||
} | ||
|
||
func getHTTPClient(driverEndpoint string) (client.API, error) { | ||
log.Printf("Using API connection for requests") | ||
|
||
endpoint, err := url.Parse(driverEndpoint) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
trans := pkg.LoggingHTTPTransport{ | ||
Transport: http.Transport{}, | ||
} | ||
|
||
httpClient := http.Client{ | ||
Transport: &trans, | ||
} | ||
|
||
return client.NewHTTPClient(&httpClient, *endpoint) | ||
} | ||
|
||
func getETCDClient(driverEndpoint string, etcdKeyPrefix string) (client.API, error) { | ||
log.Printf("Using ETCD connection for requests") | ||
|
||
trans := &http.Transport{} | ||
|
||
eCfg := etcd.Config{ | ||
Endpoints: strings.Split(driverEndpoint, ","), | ||
Transport: trans, | ||
} | ||
|
||
eClient, err := etcd.New(eCfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
kAPI := etcd.NewKeysAPI(eClient) | ||
reg := registry.NewEtcdRegistry(kAPI, etcdKeyPrefix, defaultTimeout) | ||
|
||
if msg, ok := checkVersion(reg); !ok { | ||
log.Printf(msg) | ||
} | ||
|
||
return &client.RegistryClient{Registry: reg}, nil | ||
} | ||
|
||
func getTunnelClient(driverEndpoint string, maxRetries int) (client.API, error) { | ||
log.Printf("Using Fleet Tunnel connection for requests") | ||
|
||
getSSHClient := func() (interface{}, error) { | ||
return ssh.NewSSHClient("core", hostAddr, nil, false, time.Second*10) | ||
return ssh.NewSSHClient("core", driverEndpoint, nil, false, defaultTimeout) | ||
} | ||
|
||
result, err := retry(getSSHClient, maxRetries) | ||
|
@@ -52,6 +121,15 @@ func getAPI(hostAddr string, maxRetries int) (client.API, error) { | |
return ssh.DialCommand(sshClient, cmd) | ||
} | ||
|
||
// This is needed to fake out the client - it isn't used | ||
// since we're overloading the dial method on the transport | ||
// but the client complains if it isn't set | ||
fakeHttpEndpoint, err := url.Parse("http://domain-sock") | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
trans := pkg.LoggingHTTPTransport{ | ||
Transport: http.Transport{ | ||
Dial: dial, | ||
|
@@ -62,27 +140,54 @@ func getAPI(hostAddr string, maxRetries int) (client.API, error) { | |
Transport: &trans, | ||
} | ||
|
||
// since dial() ignores the endpoint, we just need something here that | ||
// won't make the HTTP client complain. | ||
endpoint, err := url.Parse("http://domain-sock") | ||
return client.NewHTTPClient(&httpClient, *fakeHttpEndpoint) | ||
} | ||
|
||
return client.NewHTTPClient(&httpClient, *endpoint) | ||
|
||
// getAPI returns an API to Fleet. | ||
func getAPI(driver string, driverEndpoint string, maxRetries int, etcdKeyPrefix string) (client.API, error) { | ||
|
||
switch strings.ToLower(driver) { | ||
case "api": | ||
return getHTTPClient(driverEndpoint) | ||
case "etcd": | ||
return getETCDClient(driverEndpoint, etcdKeyPrefix) | ||
case "tunnel": | ||
return getTunnelClient(driverEndpoint, maxRetries) | ||
case "null": | ||
fallthrough | ||
default: | ||
return nullAPI{}, nil | ||
} | ||
} | ||
|
||
// Provider returns the ResourceProvider implemented by this package. Serve | ||
// this with the Terraform plugin helper and you are golden. | ||
func Provider() terraform.ResourceProvider { | ||
return &schema.Provider{ | ||
Schema: map[string]*schema.Schema{ | ||
"tunnel_address": &schema.Schema{ | ||
"driver": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
Optional: true, | ||
Default: "tunnel", | ||
Description: "Driver to use to connect to Fleet. Can be tunnel or api.", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems a bit at odds with the capabilities of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha, I saw the difference but wasn't sure about modifying your static setting of that tunnel socket location, I've updated that so it makes sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modify all you want. I doubt many people are using this provider, so it's probably more important that we get it right than it is to maintain backwards compatibility. I think we should more or less be able to use the code from https://github.com/coreos/fleet/blob/master/fleetctl/fleetctl.go with some modifications to get the configuration from Terraform instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh, yeah it would be good to mimic more completely how they build the client. Do you want that refactor in this PR or another one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bitglue hey Can I open a new PR for pulling in what the main fleetctl config is doing? I want to be sure I've got enough PR's for this: https://hacktoberfest.digitalocean.com/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heh, I was trying to do hacktoberfest too. Open as many PRs as you want, as long as each one has a more or less coherent purpose. |
||
}, | ||
"endpoint": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Endpoint for Fleet.", | ||
}, | ||
"connection_retries": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 12, | ||
}, | ||
"etc_key_prefix": &schema.Schema{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be named |
||
Type: schema.TypeString, | ||
Optional: true, | ||
Default: "/_coreos.com/fleet/", | ||
Description: "EtcdKeyPrefix to use for fleet", | ||
}, | ||
}, | ||
ResourcesMap: map[string]*schema.Resource{ | ||
"fleet_unit": resourceUnit(), | ||
|
@@ -92,7 +197,9 @@ func Provider() terraform.ResourceProvider { | |
} | ||
|
||
func providerConfigure(d *schema.ResourceData) (interface{}, error) { | ||
addr := d.Get("tunnel_address").(string) | ||
retries := d.Get("connection_retries").(int) | ||
return getAPI(addr, retries) | ||
driver := d.Get("driver").(string) | ||
endpoint := d.Get("endpoint").(string) | ||
etcKeyPrefix := d.Get("etc_key_prefix").(string) | ||
return getAPI(driver, endpoint, retries, etcKeyPrefix) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,7 +58,7 @@ func TestGetAPI(test *testing.T) { | |
// when the address is an empty string, we get a nullAPI | ||
var api client.API | ||
|
||
api, err := getAPI("", 1) | ||
api, err := getAPI("null", "endpoint", 1, "etcd_prefix") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem to be testing "when the address is an empty string, we get a nullAPI", though maybe it doesn't matter anymore. It used to be that if the However, this doesn't seem to work in more recent versions of Terraform, for reasons I haven't yet fully investigated. hashicorp/terraform#2430 has a bit more context. Until that's sorted out, perhaps it's best to retain the old behavior. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of the comments on that linked thread: |
||
|
||
if err != nil { | ||
test.Fatal(err) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
driver = "api"
means to use the fleet HTTP API, not frobbing etcd directly, right? If so, it's pretty unlikely the endpoint would be on port 4001 in this case.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is, that's a bad example I didn't mean to push