Merge branch 'v1.5' into master
This commit is contained in:
commit
4a7297d05c
43 changed files with 667 additions and 198 deletions
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,5 +1,32 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [v1.5.0-rc3](https://github.com/containous/traefik/tree/v1.5.0-rc3) (2017-12-20)
|
||||||
|
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc2...v1.5.0-rc3)
|
||||||
|
|
||||||
|
**Enhancements:**
|
||||||
|
- **[docker,k8s,rancher]** Support regex redirect by frontend ([#2570](https://github.com/containous/traefik/pull/2570) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[acme,docker]** Modify ACME configuration migration into KV store ([#2598](https://github.com/containous/traefik/pull/2598) by [nmengin](https://github.com/nmengin))
|
||||||
|
- **[consulcatalog]** Reload configuration when port change for one service ([#2574](https://github.com/containous/traefik/pull/2574) by [mmatur](https://github.com/mmatur))
|
||||||
|
- **[consulcatalog]** Fix bad Træfik update on Consul Catalog ([#2573](https://github.com/containous/traefik/pull/2573) by [mmatur](https://github.com/mmatur))
|
||||||
|
- **[k8s]** Add missing entrypoints template. ([#2594](https://github.com/containous/traefik/pull/2594) by [ldez](https://github.com/ldez))
|
||||||
|
- **[kv]** Fix stickiness bug due to template syntax error ([#2591](https://github.com/containous/traefik/pull/2591) by [dahefanteng](https://github.com/dahefanteng))
|
||||||
|
- **[marathon]** Update go-marathon ([#2585](https://github.com/containous/traefik/pull/2585) by [timoreimann](https://github.com/timoreimann))
|
||||||
|
- **[mesos]** Mesos: Use slave.PID.Host as task SlaveIP. ([#2590](https://github.com/containous/traefik/pull/2590) by [nemosupremo](https://github.com/nemosupremo))
|
||||||
|
- **[middleware]** Fix RawPath handling in addPrefix ([#2560](https://github.com/containous/traefik/pull/2560) by [risdenk](https://github.com/risdenk))
|
||||||
|
- **[rules]** Add non regex pathPrefix ([#2592](https://github.com/containous/traefik/pull/2592) by [emilevauge](https://github.com/emilevauge))
|
||||||
|
- **[servicefabric]** Fix backend name for Stateful services. (Service Fabric) ([#2559](https://github.com/containous/traefik/pull/2559) by [ldez](https://github.com/ldez))
|
||||||
|
- **[servicefabric]** Fix isHealthy logic. ([#2577](https://github.com/containous/traefik/pull/2577) by [ldez](https://github.com/ldez))
|
||||||
|
- **[zk]** Change Zookeeper default prefix. ([#2580](https://github.com/containous/traefik/pull/2580) by [ldez](https://github.com/ldez))
|
||||||
|
- Fix frontend redirect ([#2544](https://github.com/containous/traefik/pull/2544) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[acme]** Improve documentation for Cloudflare API key ([#2558](https://github.com/containous/traefik/pull/2558) by [mmatur](https://github.com/mmatur))
|
||||||
|
- Move rate limit documentation. ([#2588](https://github.com/containous/traefik/pull/2588) by [ldez](https://github.com/ldez))
|
||||||
|
- Grammar ([#2562](https://github.com/containous/traefik/pull/2562) by [geraldcroes](https://github.com/geraldcroes))
|
||||||
|
- Fix broken links and improve ResponseCodeRatio() description ([#2538](https://github.com/containous/traefik/pull/2538) by [mvasin](https://github.com/mvasin))
|
||||||
|
|
||||||
## [v1.5.0-rc2](https://github.com/containous/traefik/tree/v1.5.0-rc2) (2017-12-06)
|
## [v1.5.0-rc2](https://github.com/containous/traefik/tree/v1.5.0-rc2) (2017-12-06)
|
||||||
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.5.0-rc2)
|
[All Commits](https://github.com/containous/traefik/compare/v1.5.0-rc1...v1.5.0-rc2)
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,9 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
|
||||||
backend = "{{$frontend.Backend}}"
|
backend = "{{$frontend.Backend}}"
|
||||||
priority = {{$frontend.Priority}}
|
priority = {{$frontend.Priority}}
|
||||||
passHostHeader = {{$frontend.PassHostHeader}}
|
passHostHeader = {{$frontend.PassHostHeader}}
|
||||||
|
entryPoints = [{{range $frontend.EntryPoints}}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
basicAuth = [{{range $frontend.BasicAuth}}
|
basicAuth = [{{range $frontend.BasicAuth}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
@ -620,7 +623,7 @@ var _templatesKvTmpl = []byte(`{{$frontends := List .Prefix "/frontends/" }}
|
||||||
sticky = {{ getSticky . }}
|
sticky = {{ getSticky . }}
|
||||||
{{if hasStickinessLabel $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
[backends."{{$backendName}}".loadBalancer.stickiness]
|
[backends."{{$backendName}}".loadBalancer.stickiness]
|
||||||
cookieName = {{getStickinessCookieName $backend}}
|
cookieName = "{{getStickinessCookieName $backend}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
var defaultZookeeper zk.Provider
|
var defaultZookeeper zk.Provider
|
||||||
defaultZookeeper.Watch = true
|
defaultZookeeper.Watch = true
|
||||||
defaultZookeeper.Endpoint = "127.0.0.1:2181"
|
defaultZookeeper.Endpoint = "127.0.0.1:2181"
|
||||||
defaultZookeeper.Prefix = "/traefik"
|
defaultZookeeper.Prefix = "traefik"
|
||||||
defaultZookeeper.Constraints = types.Constraints{}
|
defaultZookeeper.Constraints = types.Constraints{}
|
||||||
|
|
||||||
//default Boltdb
|
//default Boltdb
|
||||||
|
|
|
@ -67,14 +67,23 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if traefikConfiguration.GlobalConfiguration.ACME != nil && len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
if traefikConfiguration.GlobalConfiguration.ACME != nil {
|
||||||
|
var object cluster.Object
|
||||||
|
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
|
||||||
// convert ACME json file to KV store
|
// convert ACME json file to KV store
|
||||||
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
|
||||||
object, err := localStore.Load()
|
object, err = localStore.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Create an empty account to create all the keys into the KV store
|
||||||
|
account := &acme.Account{}
|
||||||
|
account.Init()
|
||||||
|
object = account
|
||||||
|
}
|
||||||
|
|
||||||
meta := cluster.NewMetadata(object)
|
meta := cluster.NewMetadata(object)
|
||||||
err = meta.Marshall()
|
err = meta.Marshall()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,6 +98,11 @@ func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfigurat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Force to delete storagefile
|
||||||
|
err = kv.Delete(kv.Prefix + "/acme/storagefile")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,35 +321,6 @@ In this example, traffic routed through the first frontend will have the `X-Fram
|
||||||
!!! note
|
!!! note
|
||||||
The detailed documentation for those security headers can be found in [unrolled/secure](https://github.com/unrolled/secure#available-options).
|
The detailed documentation for those security headers can be found in [unrolled/secure](https://github.com/unrolled/secure#available-options).
|
||||||
|
|
||||||
#### Rate limiting
|
|
||||||
|
|
||||||
Rate limiting can be configured per frontend.
|
|
||||||
Multiple sets of rates can be added to each frontend, but the time periods must be unique.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[frontends]
|
|
||||||
[frontends.frontend1]
|
|
||||||
passHostHeader = true
|
|
||||||
entrypoints = ["http"]
|
|
||||||
backend = "backend1"
|
|
||||||
[frontends.frontend1.routes.test_1]
|
|
||||||
rule = "Path:/"
|
|
||||||
[frontends.frontend1.ratelimit]
|
|
||||||
extractorfunc = "client.ip"
|
|
||||||
[frontends.frontend1.ratelimit.rateset.rateset1]
|
|
||||||
period = "10s"
|
|
||||||
average = 100
|
|
||||||
burst = 200
|
|
||||||
[frontends.frontend1.ratelimit.rateset.rateset2]
|
|
||||||
period = "3s"
|
|
||||||
average = 5
|
|
||||||
burst = 10
|
|
||||||
```
|
|
||||||
|
|
||||||
In the above example, frontend1 is configured to limit requests by the client's ip address.
|
|
||||||
An average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds.
|
|
||||||
These can "burst" up to 10 and 200 in each period respectively.
|
|
||||||
|
|
||||||
### Backends
|
### Backends
|
||||||
|
|
||||||
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
|
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
|
||||||
|
|
|
@ -20,6 +20,12 @@ See also [Let's Encrypt examples](/user-guide/examples/#lets-encrypt-support) an
|
||||||
#
|
#
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
|
|
||||||
|
# File used for certificates storage.
|
||||||
|
#
|
||||||
|
# Optional (Deprecated)
|
||||||
|
#
|
||||||
|
#storageFile = "acme.json"
|
||||||
|
|
||||||
# File or key used for certificates storage.
|
# File or key used for certificates storage.
|
||||||
#
|
#
|
||||||
# Required
|
# Required
|
||||||
|
@ -55,7 +61,7 @@ entryPoint = "https"
|
||||||
#
|
#
|
||||||
# acmeLogging = true
|
# acmeLogging = true
|
||||||
|
|
||||||
# Enable on demand certificate.
|
# Enable on demand certificate. (Deprecated)
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
|
@ -89,6 +95,10 @@ entryPoint = "https"
|
||||||
# main = "local4.com"
|
# main = "local4.com"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
ACME entryPoint has to be relied to the port 443, otherwise ACME Challenges can not be done.
|
||||||
|
It's a Let's Encrypt limitation as described on the [community forum](https://community.letsencrypt.org/t/support-for-ports-other-than-80-and-443/3419/72).
|
||||||
|
|
||||||
### `storage`
|
### `storage`
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
@ -100,7 +110,7 @@ storage = "acme.json"
|
||||||
|
|
||||||
File or key used for certificates storage.
|
File or key used for certificates storage.
|
||||||
|
|
||||||
**WARNING** If you use Traefik in Docker, you have 2 options:
|
**WARNING** If you use Træfik in Docker, you have 2 options:
|
||||||
|
|
||||||
- create a file on your host and mount it as a volume:
|
- create a file on your host and mount it as a volume:
|
||||||
```toml
|
```toml
|
||||||
|
@ -118,6 +128,14 @@ storage = "/etc/traefik/acme/acme.json"
|
||||||
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
`storage` replaces `storageFile` which is deprecated.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
During Træfik configuration migration from a configuration file to a KV store (thanks to `storeconfig` subcommand as described [here](/user-guide/kv-config/#store-configuration-in-key-value-store)), if ACME certificates have to be migrated too, use both `storageFile` and `storage`.
|
||||||
|
`storageFile` will contain the path to the `acme.json` file to migrate.
|
||||||
|
`storage` will contain the key where the certificates will be stored.
|
||||||
|
|
||||||
### `dnsProvider`
|
### `dnsProvider`
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
@ -146,7 +164,7 @@ Select the provider that matches the DNS domain that will host the challenge TXT
|
||||||
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` |
|
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` |
|
||||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` |
|
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, `GCE_SERVICE_ACCOUNT_FILE` |
|
||||||
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` |
|
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` |
|
||||||
| manual | - | none, but run Traefik interactively & turn on `acmeLogging` to see instructions & press <kbd>Enter</kbd>. |
|
| manual | - | none, but run Træfik interactively & turn on `acmeLogging` to see instructions & press <kbd>Enter</kbd>. |
|
||||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` |
|
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` |
|
||||||
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` |
|
| [Ns1](https://ns1.com/) | `ns1` | `NS1_API_KEY` |
|
||||||
| [Open Telekom Cloud](https://cloud.telekom.de/en/) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` |
|
| [Open Telekom Cloud](https://cloud.telekom.de/en/) | `otc` | `OTC_DOMAIN_NAME`, `OTC_USER_NAME`, `OTC_PASSWORD`, `OTC_PROJECT_NAME`, `OTC_IDENTITY_ENDPOINT` |
|
||||||
|
@ -171,7 +189,7 @@ If `delayDontCheckDNS` is greater than zero, avoid this & instead just wait so m
|
||||||
|
|
||||||
Useful if internal networks block external DNS queries.
|
Useful if internal networks block external DNS queries.
|
||||||
|
|
||||||
### `onDemand`
|
### `onDemand` (Deprecated)
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[acme]
|
[acme]
|
||||||
|
@ -188,7 +206,10 @@ This will request a certificate from Let's Encrypt during the first TLS handshak
|
||||||
TLS handshakes will be slow when requesting a hostname certificate for the first time, this can lead to DoS attacks.
|
TLS handshakes will be slow when requesting a hostname certificate for the first time, this can lead to DoS attacks.
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits)
|
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
This option is deprecated.
|
||||||
|
|
||||||
### `onHostRule`
|
### `onHostRule`
|
||||||
|
|
||||||
|
@ -238,7 +259,7 @@ main = "local4.com"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can provide SANs (alternative domains) to each main domain.
|
You can provide SANs (alternative domains) to each main domain.
|
||||||
All domains must have A/AAAA records pointing to Traefik.
|
All domains must have A/AAAA records pointing to Træfik.
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits).
|
||||||
|
|
|
@ -27,9 +27,9 @@ watch = true
|
||||||
# Prefix used for KV store.
|
# Prefix used for KV store.
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
# Default: "/traefik"
|
# Default: "traefik"
|
||||||
#
|
#
|
||||||
prefix = "/traefik"
|
prefix = "traefik"
|
||||||
|
|
||||||
# Override default configuration template.
|
# Override default configuration template.
|
||||||
# For advanced users :)
|
# For advanced users :)
|
||||||
|
|
|
@ -277,6 +277,36 @@ Custom error pages are easiest to implement using the file provider.
|
||||||
For dynamic providers, the corresponding template file needs to be customized accordingly and referenced in the Traefik configuration.
|
For dynamic providers, the corresponding template file needs to be customized accordingly and referenced in the Traefik configuration.
|
||||||
|
|
||||||
|
|
||||||
|
## Rate limiting
|
||||||
|
|
||||||
|
Rate limiting can be configured per frontend.
|
||||||
|
Multiple sets of rates can be added to each frontend, but the time periods must be unique.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[frontends]
|
||||||
|
[frontends.frontend1]
|
||||||
|
passHostHeader = true
|
||||||
|
entrypoints = ["http"]
|
||||||
|
backend = "backend1"
|
||||||
|
[frontends.frontend1.routes.test_1]
|
||||||
|
rule = "Path:/"
|
||||||
|
[frontends.frontend1.ratelimit]
|
||||||
|
extractorfunc = "client.ip"
|
||||||
|
[frontends.frontend1.ratelimit.rateset.rateset1]
|
||||||
|
period = "10s"
|
||||||
|
average = 100
|
||||||
|
burst = 200
|
||||||
|
[frontends.frontend1.ratelimit.rateset.rateset2]
|
||||||
|
period = "3s"
|
||||||
|
average = 5
|
||||||
|
burst = 10
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, frontend1 is configured to limit requests by the client's ip address.
|
||||||
|
An average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds.
|
||||||
|
These can "burst" up to 10 and 200 in each period respectively.
|
||||||
|
|
||||||
|
|
||||||
## Retry Configuration
|
## Retry Configuration
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|
|
@ -38,16 +38,7 @@ services:
|
||||||
|
|
||||||
etcdctl-ping:
|
etcdctl-ping:
|
||||||
image: tenstartups/etcdctl
|
image: tenstartups/etcdctl
|
||||||
command: --endpoints=[10.0.1.12:2379] get "traefik/acme/storagefile"
|
command: --endpoints=[10.0.1.12:2379] get "traefik/acme/storage"
|
||||||
environment:
|
|
||||||
ETCDCTL_DIAL_: "TIMEOUT 10s"
|
|
||||||
ETCDCTL_API : "3"
|
|
||||||
networks:
|
|
||||||
- net
|
|
||||||
|
|
||||||
etcdctl-rm:
|
|
||||||
image: tenstartups/etcdctl
|
|
||||||
command: --endpoints=[10.0.1.12:2379] del "/traefik/acme/storagefile"
|
|
||||||
environment:
|
environment:
|
||||||
ETCDCTL_DIAL_: "TIMEOUT 10s"
|
ETCDCTL_DIAL_: "TIMEOUT 10s"
|
||||||
ETCDCTL_API : "3"
|
ETCDCTL_API : "3"
|
||||||
|
@ -129,7 +120,6 @@ services:
|
||||||
image: containous/traefik
|
image: containous/traefik
|
||||||
volumes:
|
volumes:
|
||||||
- "./traefik.toml:/traefik.toml:ro"
|
- "./traefik.toml:/traefik.toml:ro"
|
||||||
- "./acme.json:/acme.json:ro"
|
|
||||||
command: storeconfig --debug
|
command: storeconfig --debug
|
||||||
networks:
|
networks:
|
||||||
- net
|
- net
|
||||||
|
|
|
@ -32,15 +32,6 @@ delete_services() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Init the environment : get IP address and create needed files
|
|
||||||
init_acme_json() {
|
|
||||||
echo "CREATE empty acme.json file"
|
|
||||||
rm -f $basedir/acme.json && \
|
|
||||||
touch $basedir/acme.json && \
|
|
||||||
echo "{}" > $basedir/acme.json && \
|
|
||||||
chmod 600 $basedir/acme.json # Needed for ACME
|
|
||||||
}
|
|
||||||
|
|
||||||
start_consul() {
|
start_consul() {
|
||||||
up_environment consul
|
up_environment consul
|
||||||
waiting_counter=12
|
waiting_counter=12
|
||||||
|
@ -76,7 +67,6 @@ start_etcd3() {
|
||||||
}
|
}
|
||||||
|
|
||||||
start_storeconfig_consul() {
|
start_storeconfig_consul() {
|
||||||
init_acme_json
|
|
||||||
# Create traefik.toml with consul provider
|
# Create traefik.toml with consul provider
|
||||||
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
||||||
echo '
|
echo '
|
||||||
|
@ -85,29 +75,13 @@ start_storeconfig_consul() {
|
||||||
watch = true
|
watch = true
|
||||||
prefix = "traefik"' >> $basedir/traefik.toml
|
prefix = "traefik"' >> $basedir/traefik.toml
|
||||||
up_environment traefik-storeconfig
|
up_environment traefik-storeconfig
|
||||||
rm -f $basedir/traefik.toml && rm -f $basedir/acme.json
|
rm -f $basedir/traefik.toml
|
||||||
# Delete acme-storage-file key
|
|
||||||
waiting_counter=5
|
waiting_counter=5
|
||||||
# Not start Traefik store config if consul is not started
|
delete_services traefik-storeconfig
|
||||||
echo "Delete storage file key..."
|
|
||||||
while [[ -z $(curl -s http://10.0.1.2:8500/v1/kv/traefik/acme/storagefile) && $waiting_counter -gt 0 ]]; do
|
|
||||||
sleep 5
|
|
||||||
let waiting_counter-=1
|
|
||||||
done
|
|
||||||
if [[ $waiting_counter -eq 0 ]]; then
|
|
||||||
echo "[WARN] Unable to get storagefile key in consul"
|
|
||||||
else
|
|
||||||
curl -s --request DELETE http://10.0.1.2:8500/v1/kv/traefik/acme/storagefile
|
|
||||||
ret=$1
|
|
||||||
if [[ $ret -ne 0 ]]; then
|
|
||||||
echo "[ERROR] Unable to delete storagefile key from consul kv."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_storeconfig_etcd3() {
|
start_storeconfig_etcd3() {
|
||||||
init_acme_json
|
|
||||||
# Create traefik.toml with consul provider
|
# Create traefik.toml with consul provider
|
||||||
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
cp $basedir/traefik.toml.tmpl $basedir/traefik.toml
|
||||||
echo '
|
echo '
|
||||||
|
@ -117,20 +91,15 @@ start_storeconfig_etcd3() {
|
||||||
prefix = "/traefik"
|
prefix = "/traefik"
|
||||||
useAPIV3 = true' >> $basedir/traefik.toml
|
useAPIV3 = true' >> $basedir/traefik.toml
|
||||||
up_environment traefik-storeconfig
|
up_environment traefik-storeconfig
|
||||||
rm -f $basedir/traefik.toml && rm -f $basedir/acme.json
|
rm -f $basedir/traefik.toml
|
||||||
# Delete acme-storage-file key
|
|
||||||
waiting_counter=5
|
waiting_counter=5
|
||||||
# Not start Traefik store config if consul is not started
|
# Don't start Traefik store config if ETCD3 is not started
|
||||||
echo "Delete storage file key..."
|
echo "Delete storage file key..."
|
||||||
while [[ $(docker-compose -f $doc_file up --exit-code-from etcdctl-ping etcdctl-ping &>/dev/null) -ne 0 && $waiting_counter -gt 0 ]]; do
|
while [[ $(docker-compose -f $doc_file up --exit-code-from etcdctl-ping etcdctl-ping &>/dev/null) -ne 0 && $waiting_counter -gt 0 ]]; do
|
||||||
sleep 5
|
sleep 5
|
||||||
let waiting_counter-=1
|
let waiting_counter-=1
|
||||||
done
|
done
|
||||||
# Not start Traefik store config if consul is not started
|
delete_services traefik-storeconfig etcdctl-ping
|
||||||
echo "Delete storage file key from ETCD3..."
|
|
||||||
|
|
||||||
up_environment etcdctl-rm && \
|
|
||||||
delete_services etcdctl-rm traefik-storeconfig etcdctl-ping
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_traefik() {
|
start_traefik() {
|
||||||
|
|
|
@ -12,7 +12,6 @@ defaultEntryPoints = ["http", "https"]
|
||||||
[acme]
|
[acme]
|
||||||
email = "test@traefik.io"
|
email = "test@traefik.io"
|
||||||
storage = "traefik/acme/account"
|
storage = "traefik/acme/account"
|
||||||
storageFile = "/acme.json"
|
|
||||||
entryPoint = "https"
|
entryPoint = "https"
|
||||||
OnHostRule = true
|
OnHostRule = true
|
||||||
caServer = "http://traefik.boulder.com:4000/directory"
|
caServer = "http://traefik.boulder.com:4000/directory"
|
||||||
|
|
6
glide.lock
generated
6
glide.lock
generated
|
@ -1,4 +1,4 @@
|
||||||
hash: f0d5ef854a4c115306c63c15320b595c29f715950eaf5f18418149886ecda400
|
hash: d7f811ac4a011308c6e1f73b618215dee90dae6cace9511f66d4b63d916a337a
|
||||||
updated: 2017-12-15T10:34:41.246378337+01:00
|
updated: 2017-12-15T10:34:41.246378337+01:00
|
||||||
imports:
|
imports:
|
||||||
- name: cloud.google.com/go
|
- name: cloud.google.com/go
|
||||||
|
@ -94,7 +94,7 @@ imports:
|
||||||
- name: github.com/containous/staert
|
- name: github.com/containous/staert
|
||||||
version: af517d5b70db9c4b0505e0144fcc62b054057d2a
|
version: af517d5b70db9c4b0505e0144fcc62b054057d2a
|
||||||
- name: github.com/containous/traefik-extra-service-fabric
|
- name: github.com/containous/traefik-extra-service-fabric
|
||||||
version: c01c1ef60ed612c5e42c1ceae0c6f92e67619cc3
|
version: ca1fb57108293caad285b1c366b763f6c6ab71c9
|
||||||
- name: github.com/coreos/bbolt
|
- name: github.com/coreos/bbolt
|
||||||
version: 3c6cbfb299c11444eb2f8c9d48f0d2ce09157423
|
version: 3c6cbfb299c11444eb2f8c9d48f0d2ce09157423
|
||||||
- name: github.com/coreos/etcd
|
- name: github.com/coreos/etcd
|
||||||
|
@ -261,7 +261,7 @@ imports:
|
||||||
- name: github.com/fatih/color
|
- name: github.com/fatih/color
|
||||||
version: 62e9147c64a1ed519147b62a56a14e83e2be02c1
|
version: 62e9147c64a1ed519147b62a56a14e83e2be02c1
|
||||||
- name: github.com/gambol99/go-marathon
|
- name: github.com/gambol99/go-marathon
|
||||||
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
|
version: 03b46169666c53b9cc953b875ac5714e5103e064
|
||||||
- name: github.com/ghodss/yaml
|
- name: github.com/ghodss/yaml
|
||||||
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
||||||
- name: github.com/go-ini/ini
|
- name: github.com/go-ini/ini
|
||||||
|
|
|
@ -12,7 +12,7 @@ import:
|
||||||
- package: github.com/cenk/backoff
|
- package: github.com/cenk/backoff
|
||||||
- package: github.com/containous/flaeg
|
- package: github.com/containous/flaeg
|
||||||
- package: github.com/containous/traefik-extra-service-fabric
|
- package: github.com/containous/traefik-extra-service-fabric
|
||||||
version: v1.0.4
|
version: v1.0.5
|
||||||
- package: github.com/vulcand/oxy
|
- package: github.com/vulcand/oxy
|
||||||
version: 7b6e758ab449705195df638765c4ca472248908a
|
version: 7b6e758ab449705195df638765c4ca472248908a
|
||||||
repo: https://github.com/containous/oxy.git
|
repo: https://github.com/containous/oxy.git
|
||||||
|
|
|
@ -81,7 +81,7 @@ func taskRecords(st state.State) []state.Task {
|
||||||
for _, task := range f.Tasks {
|
for _, task := range f.Tasks {
|
||||||
for _, slave := range st.Slaves {
|
for _, slave := range st.Slaves {
|
||||||
if task.SlaveID == slave.ID {
|
if task.SlaveID == slave.ID {
|
||||||
task.SlaveIP = slave.Hostname
|
task.SlaveIP = slave.PID.Host
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/containous/traefik/provider/label"
|
"github.com/containous/traefik/provider/label"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
"github.com/mesos/mesos-go/upid"
|
||||||
"github.com/mesosphere/mesos-dns/records/state"
|
"github.com/mesosphere/mesos-dns/records/state"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -262,6 +263,9 @@ func TestTaskRecords(t *testing.T) {
|
||||||
ID: "s_id",
|
ID: "s_id",
|
||||||
Hostname: "127.0.0.1",
|
Hostname: "127.0.0.1",
|
||||||
}
|
}
|
||||||
|
slave.PID.UPID = &upid.UPID{}
|
||||||
|
slave.PID.Host = slave.Hostname
|
||||||
|
|
||||||
var taskState = state.State{
|
var taskState = state.State{
|
||||||
Slaves: []state.Slave{slave},
|
Slaves: []state.Slave{slave},
|
||||||
Frameworks: []state.Framework{framework},
|
Frameworks: []state.Framework{framework},
|
||||||
|
|
|
@ -54,11 +54,32 @@ func (r *Rules) path(paths ...string) *mux.Route {
|
||||||
func (r *Rules) pathPrefix(paths ...string) *mux.Route {
|
func (r *Rules) pathPrefix(paths ...string) *mux.Route {
|
||||||
router := r.route.route.Subrouter()
|
router := r.route.route.Subrouter()
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
router.PathPrefix(strings.TrimSpace(path))
|
buildPath(path, router)
|
||||||
}
|
}
|
||||||
return r.route.route
|
return r.route.route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildPath(path string, router *mux.Router) {
|
||||||
|
cleanPath := strings.TrimSpace(path)
|
||||||
|
// {} are used to define a regex pattern in http://www.gorillatoolkit.org/pkg/mux.
|
||||||
|
// if we find a { in the path, that means we use regex, then the gorilla/mux implementation is chosen
|
||||||
|
// otherwise, we use a lightweight implementation
|
||||||
|
if strings.Contains(cleanPath, "{") {
|
||||||
|
router.PathPrefix(cleanPath)
|
||||||
|
} else {
|
||||||
|
m := &prefixMatcher{prefix: cleanPath}
|
||||||
|
router.NewRoute().MatcherFunc(m.Match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type prefixMatcher struct {
|
||||||
|
prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *prefixMatcher) Match(r *http.Request, _ *mux.RouteMatch) bool {
|
||||||
|
return strings.HasPrefix(r.URL.Path, m.prefix) || strings.HasPrefix(r.URL.Path, m.prefix+"/")
|
||||||
|
}
|
||||||
|
|
||||||
type bySize []string
|
type bySize []string
|
||||||
|
|
||||||
func (a bySize) Len() int { return len(a) }
|
func (a bySize) Len() int { return len(a) }
|
||||||
|
@ -111,7 +132,7 @@ func (r *Rules) pathPrefixStrip(paths ...string) *mux.Route {
|
||||||
r.route.stripPrefixes = paths
|
r.route.stripPrefixes = paths
|
||||||
router := r.route.route.Subrouter()
|
router := r.route.route.Subrouter()
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
router.PathPrefix(strings.TrimSpace(path))
|
buildPath(path, router)
|
||||||
}
|
}
|
||||||
return r.route.route
|
return r.route.route
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,3 +192,67 @@ type fakeHandler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) {}
|
func (h *fakeHandler) ServeHTTP(http.ResponseWriter, *http.Request) {}
|
||||||
|
|
||||||
|
func TestPathPrefix(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
path string
|
||||||
|
urls map[string]bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "leading slash",
|
||||||
|
path: "/bar",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://foo.com/bar": true,
|
||||||
|
"http://foo.com/bar/": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "leading trailing slash",
|
||||||
|
path: "/bar/",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://foo.com/bar": false,
|
||||||
|
"http://foo.com/bar/": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "no slash",
|
||||||
|
path: "bar",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://foo.com/bar": false,
|
||||||
|
"http://foo.com/bar/": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "trailing slash",
|
||||||
|
path: "bar/",
|
||||||
|
urls: map[string]bool{
|
||||||
|
"http://foo.com/bar": false,
|
||||||
|
"http://foo.com/bar/": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rls := &Rules{
|
||||||
|
route: &serverRoute{
|
||||||
|
route: &mux.Route{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := rls.pathPrefix(test.path)
|
||||||
|
|
||||||
|
for testURL, expectedMatch := range test.urls {
|
||||||
|
req := testhelpers.MustNewRequest(http.MethodGet, testURL, nil)
|
||||||
|
match := rt.Match(req, &mux.RouteMatch{})
|
||||||
|
if match != expectedMatch {
|
||||||
|
t.Errorf("Error matching %s with %s, got %v expected %v", test.path, testURL, match, expectedMatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
backend = "{{$frontend.Backend}}"
|
backend = "{{$frontend.Backend}}"
|
||||||
priority = {{$frontend.Priority}}
|
priority = {{$frontend.Priority}}
|
||||||
passHostHeader = {{$frontend.PassHostHeader}}
|
passHostHeader = {{$frontend.PassHostHeader}}
|
||||||
|
entryPoints = [{{range $frontend.EntryPoints}}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
basicAuth = [{{range $frontend.BasicAuth}}
|
basicAuth = [{{range $frontend.BasicAuth}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
sticky = {{ getSticky . }}
|
sticky = {{ getSticky . }}
|
||||||
{{if hasStickinessLabel $backend}}
|
{{if hasStickinessLabel $backend}}
|
||||||
[backends."{{$backendName}}".loadBalancer.stickiness]
|
[backends."{{$backendName}}".loadBalancer.stickiness]
|
||||||
cookieName = {{getStickinessCookieName $backend}}
|
cookieName = "{{getStickinessCookieName $backend}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
2
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
2
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
|
@ -303,7 +303,7 @@ func isPrimary(instance replicaInstance) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHealthy(instanceData *sf.ReplicaItemBase) bool {
|
func isHealthy(instanceData *sf.ReplicaItemBase) bool {
|
||||||
return instanceData != nil && (instanceData.ReplicaStatus == "Ready" || instanceData.HealthState != "Error")
|
return instanceData != nil && (instanceData.ReplicaStatus == "Ready" && instanceData.HealthState != "Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasHTTPEndpoint(instanceData *sf.ReplicaItemBase) bool {
|
func hasHTTPEndpoint(instanceData *sf.ReplicaItemBase) bool {
|
||||||
|
|
56
vendor/github.com/gambol99/go-marathon/application.go
generated
vendored
56
vendor/github.com/gambol99/go-marathon/application.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -64,7 +64,8 @@ type Application struct {
|
||||||
CPUs float64 `json:"cpus,omitempty"`
|
CPUs float64 `json:"cpus,omitempty"`
|
||||||
GPUs *float64 `json:"gpus,omitempty"`
|
GPUs *float64 `json:"gpus,omitempty"`
|
||||||
Disk *float64 `json:"disk,omitempty"`
|
Disk *float64 `json:"disk,omitempty"`
|
||||||
Env *map[string]string `json:"env,omitempty"`
|
// Contains non-secret environment variables. Secrets environment variables are part of the Secrets map.
|
||||||
|
Env *map[string]string `json:"-"`
|
||||||
Executor *string `json:"executor,omitempty"`
|
Executor *string `json:"executor,omitempty"`
|
||||||
HealthChecks *[]HealthCheck `json:"healthChecks,omitempty"`
|
HealthChecks *[]HealthCheck `json:"healthChecks,omitempty"`
|
||||||
ReadinessChecks *[]ReadinessCheck `json:"readinessChecks,omitempty"`
|
ReadinessChecks *[]ReadinessCheck `json:"readinessChecks,omitempty"`
|
||||||
|
@ -99,6 +100,8 @@ type Application struct {
|
||||||
LastTaskFailure *LastTaskFailure `json:"lastTaskFailure,omitempty"`
|
LastTaskFailure *LastTaskFailure `json:"lastTaskFailure,omitempty"`
|
||||||
Fetch *[]Fetch `json:"fetch,omitempty"`
|
Fetch *[]Fetch `json:"fetch,omitempty"`
|
||||||
IPAddressPerTask *IPAddressPerTask `json:"ipAddress,omitempty"`
|
IPAddressPerTask *IPAddressPerTask `json:"ipAddress,omitempty"`
|
||||||
|
Residency *Residency `json:"residency,omitempty"`
|
||||||
|
Secrets *map[string]Secret `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationVersions is a collection of application versions for a specific app in marathon
|
// ApplicationVersions is a collection of application versions for a specific app in marathon
|
||||||
|
@ -149,6 +152,14 @@ type Stats struct {
|
||||||
LifeTime map[string]float64 `json:"lifeTime"`
|
LifeTime map[string]float64 `json:"lifeTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secret is the environment variable and secret store path associated with a secret.
|
||||||
|
// The value for EnvVar is populated from the env field, and Source is populated from
|
||||||
|
// the secrets field of the application json.
|
||||||
|
type Secret struct {
|
||||||
|
EnvVar string
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
// SetIPAddressPerTask defines that the application will have a IP address defines by a external agent.
|
// SetIPAddressPerTask defines that the application will have a IP address defines by a external agent.
|
||||||
// This configuration is not allowed to be used with Port or PortDefinitions. Thus, the implementation
|
// This configuration is not allowed to be used with Port or PortDefinitions. Thus, the implementation
|
||||||
// clears both.
|
// clears both.
|
||||||
|
@ -375,6 +386,28 @@ func (r *Application) EmptyEnvs() *Application {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddSecret adds a secret declaration
|
||||||
|
// envVar: the name of the environment variable
|
||||||
|
// name: the name of the secret
|
||||||
|
// source: the source ID of the secret
|
||||||
|
func (r *Application) AddSecret(envVar, name, source string) *Application {
|
||||||
|
if r.Secrets == nil {
|
||||||
|
r.EmptySecrets()
|
||||||
|
}
|
||||||
|
(*r.Secrets)[name] = Secret{EnvVar: envVar, Source: source}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptySecrets explicitly empties the secrets -- use this if you need to empty
|
||||||
|
// the secrets of an application that already has secrets set (setting secrets to nil will
|
||||||
|
// keep the current value)
|
||||||
|
func (r *Application) EmptySecrets() *Application {
|
||||||
|
r.Secrets = &map[string]Secret{}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// SetExecutor sets the executor
|
// SetExecutor sets the executor
|
||||||
func (r *Application) SetExecutor(executor string) *Application {
|
func (r *Application) SetExecutor(executor string) *Application {
|
||||||
r.Executor = &executor
|
r.Executor = &executor
|
||||||
|
@ -571,6 +604,23 @@ func (r *Application) EmptyUnreachableStrategy() *Application {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetResidency sets behavior for resident applications, an application is resident when
|
||||||
|
// it has local persistent volumes set
|
||||||
|
func (r *Application) SetResidency(whenLost TaskLostBehaviorType) *Application {
|
||||||
|
r.Residency = &Residency{
|
||||||
|
TaskLostBehavior: whenLost,
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyResidency explicitly empties the residency -- use this if
|
||||||
|
// you need to empty the residency of an application that already has
|
||||||
|
// the residency set (setting it to nil will keep the current value).
|
||||||
|
func (r *Application) EmptyResidency() *Application {
|
||||||
|
r.Residency = &Residency{}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the json representation of this application
|
// String returns the json representation of this application
|
||||||
func (r *Application) String() string {
|
func (r *Application) String() string {
|
||||||
s, err := json.MarshalIndent(r, "", " ")
|
s, err := json.MarshalIndent(r, "", " ")
|
||||||
|
@ -639,7 +689,7 @@ func (r *marathonClient) ApplicationVersions(name string) (*ApplicationVersions,
|
||||||
// name: the id used to identify the application
|
// name: the id used to identify the application
|
||||||
// version: the version (normally a timestamp) you wish to change to
|
// version: the version (normally a timestamp) you wish to change to
|
||||||
func (r *marathonClient) SetApplicationVersion(name string, version *ApplicationVersion) (*DeploymentID, error) {
|
func (r *marathonClient) SetApplicationVersion(name string, version *ApplicationVersion) (*DeploymentID, error) {
|
||||||
path := fmt.Sprintf(buildPath(name))
|
path := buildPath(name)
|
||||||
deploymentID := new(DeploymentID)
|
deploymentID := new(DeploymentID)
|
||||||
if err := r.apiPut(path, version, deploymentID); err != nil {
|
if err := r.apiPut(path, version, deploymentID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
106
vendor/github.com/gambol99/go-marathon/application_marshalling.go
generated
vendored
Normal file
106
vendor/github.com/gambol99/go-marathon/application_marshalling.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package marathon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alias aliases the Application struct so that it will be marshaled/unmarshaled automatically
|
||||||
|
type Alias Application
|
||||||
|
|
||||||
|
// TmpEnvSecret holds the secret values deserialized from the environment variables field
|
||||||
|
type TmpEnvSecret struct {
|
||||||
|
Secret string `json:"secret,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TmpSecret holds the deserialized secrets field in a Marathon application configuration
|
||||||
|
type TmpSecret struct {
|
||||||
|
Source string `json:"source,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals the given Application JSON as expected except for environment variables and secrets.
|
||||||
|
// Environment varialbes are stored in the Env field. Secrets, including the environment variable part,
|
||||||
|
// are stored in the Secrets field.
|
||||||
|
func (app *Application) UnmarshalJSON(b []byte) error {
|
||||||
|
aux := &struct {
|
||||||
|
*Alias
|
||||||
|
Env map[string]interface{} `json:"env"`
|
||||||
|
Secrets map[string]TmpSecret `json:"secrets"`
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(app),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(b, aux); err != nil {
|
||||||
|
return fmt.Errorf("malformed application definition %v", err)
|
||||||
|
}
|
||||||
|
env := &map[string]string{}
|
||||||
|
secrets := &map[string]Secret{}
|
||||||
|
|
||||||
|
for envName, genericEnvValue := range aux.Env {
|
||||||
|
switch envValOrSecret := genericEnvValue.(type) {
|
||||||
|
case string:
|
||||||
|
(*env)[envName] = envValOrSecret
|
||||||
|
case map[string]interface{}:
|
||||||
|
for secret, secretStore := range envValOrSecret {
|
||||||
|
if secStore, ok := secretStore.(string); ok && secret == "secret" {
|
||||||
|
(*secrets)[secStore] = Secret{EnvVar: envName}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unexpected secret field %v or value type %T", secret, envValOrSecret[secret])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected environment variable type %T", envValOrSecret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.Env = env
|
||||||
|
for k, v := range aux.Secrets {
|
||||||
|
tmp := (*secrets)[k]
|
||||||
|
tmp.Source = v.Source
|
||||||
|
(*secrets)[k] = tmp
|
||||||
|
}
|
||||||
|
app.Secrets = secrets
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the given Application as expected except for environment variables and secrets,
|
||||||
|
// which are marshaled from specialized structs. The environment variable piece of the secrets and other
|
||||||
|
// normal environment variables are combined and marshaled to the env field. The secrets and the related
|
||||||
|
// source are marshaled into the secrets field.
|
||||||
|
func (app *Application) MarshalJSON() ([]byte, error) {
|
||||||
|
env := make(map[string]interface{})
|
||||||
|
secrets := make(map[string]TmpSecret)
|
||||||
|
|
||||||
|
if app.Env != nil {
|
||||||
|
for k, v := range *app.Env {
|
||||||
|
env[string(k)] = string(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if app.Secrets != nil {
|
||||||
|
for k, v := range *app.Secrets {
|
||||||
|
env[v.EnvVar] = TmpEnvSecret{Secret: k}
|
||||||
|
secrets[k] = TmpSecret{v.Source}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aux := &struct {
|
||||||
|
*Alias
|
||||||
|
Env map[string]interface{} `json:"env,omitempty"`
|
||||||
|
Secrets map[string]TmpSecret `json:"secrets,omitempty"`
|
||||||
|
}{Alias: (*Alias)(app), Env: env, Secrets: secrets}
|
||||||
|
|
||||||
|
return json.Marshal(aux)
|
||||||
|
}
|
76
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
76
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -24,6 +24,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -154,6 +155,24 @@ var (
|
||||||
ErrMarathonDown = errors.New("all the Marathon hosts are presently down")
|
ErrMarathonDown = errors.New("all the Marathon hosts are presently down")
|
||||||
// ErrTimeoutError is thrown when the operation has timed out
|
// ErrTimeoutError is thrown when the operation has timed out
|
||||||
ErrTimeoutError = errors.New("the operation has timed out")
|
ErrTimeoutError = errors.New("the operation has timed out")
|
||||||
|
|
||||||
|
// Default HTTP client used for SSE subscription requests
|
||||||
|
// It is invalid to set client.Timeout because it includes time to read response so
|
||||||
|
// set dial, tls handshake and response header timeouts instead
|
||||||
|
defaultHTTPSSEClient = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
ResponseHeaderTimeout: 10 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default HTTP client used for non SSE requests
|
||||||
|
defaultHTTPClient = &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// EventsChannelContext holds contextual data for an EventsChannel.
|
// EventsChannelContext holds contextual data for an EventsChannel.
|
||||||
|
@ -177,8 +196,8 @@ type marathonClient struct {
|
||||||
hosts *cluster
|
hosts *cluster
|
||||||
// a map of service you wish to listen to
|
// a map of service you wish to listen to
|
||||||
listeners map[EventsChannel]EventsChannelContext
|
listeners map[EventsChannel]EventsChannelContext
|
||||||
// a custom logger for debug log messages
|
// a custom log function for debug messages
|
||||||
debugLog *log.Logger
|
debugLog func(format string, v ...interface{})
|
||||||
// the marathon HTTP client to ensure consistency in requests
|
// the marathon HTTP client to ensure consistency in requests
|
||||||
client *httpClient
|
client *httpClient
|
||||||
}
|
}
|
||||||
|
@ -196,9 +215,18 @@ type newRequestError struct {
|
||||||
// NewClient creates a new marathon client
|
// NewClient creates a new marathon client
|
||||||
// config: the configuration to use
|
// config: the configuration to use
|
||||||
func NewClient(config Config) (Marathon, error) {
|
func NewClient(config Config) (Marathon, error) {
|
||||||
// step: if no http client, set to default
|
// step: if the SSE HTTP client is missing, prefer a configured regular
|
||||||
|
// client, and otherwise use the default SSE HTTP client.
|
||||||
|
if config.HTTPSSEClient == nil {
|
||||||
|
config.HTTPSSEClient = defaultHTTPSSEClient
|
||||||
|
if config.HTTPClient != nil {
|
||||||
|
config.HTTPSSEClient = config.HTTPClient
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// step: if a regular HTTP client is missing, use the default one.
|
||||||
if config.HTTPClient == nil {
|
if config.HTTPClient == nil {
|
||||||
config.HTTPClient = http.DefaultClient
|
config.HTTPClient = defaultHTTPClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// step: if no polling wait time is set, default to 500 milliseconds.
|
// step: if no polling wait time is set, default to 500 milliseconds.
|
||||||
|
@ -215,16 +243,19 @@ func NewClient(config Config) (Marathon, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLogOutput := config.LogOutput
|
debugLog := func(string, ...interface{}) {}
|
||||||
if debugLogOutput == nil {
|
if config.LogOutput != nil {
|
||||||
debugLogOutput = ioutil.Discard
|
logger := log.New(config.LogOutput, "", 0)
|
||||||
|
debugLog = func(format string, v ...interface{}) {
|
||||||
|
logger.Printf(format, v...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &marathonClient{
|
return &marathonClient{
|
||||||
config: config,
|
config: config,
|
||||||
listeners: make(map[EventsChannel]EventsChannelContext),
|
listeners: make(map[EventsChannel]EventsChannelContext),
|
||||||
hosts: hosts,
|
hosts: hosts,
|
||||||
debugLog: log.New(debugLogOutput, "", 0),
|
debugLog: debugLog,
|
||||||
client: client,
|
client: client,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -280,7 +311,7 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.hosts.markDown(member)
|
r.hosts.markDown(member)
|
||||||
// step: attempt the request on another member
|
// step: attempt the request on another member
|
||||||
r.debugLog.Printf("apiCall(): request failed on host: %s, error: %s, trying another\n", member, err)
|
r.debugLog("apiCall(): request failed on host: %s, error: %s, trying another", member, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -292,9 +323,9 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(requestBody) > 0 {
|
if len(requestBody) > 0 {
|
||||||
r.debugLog.Printf("apiCall(): %v %v %s returned %v %s\n", request.Method, request.URL.String(), requestBody, response.Status, oneLogLine(respBody))
|
r.debugLog("apiCall(): %v %v %s returned %v %s", request.Method, request.URL.String(), requestBody, response.Status, oneLogLine(respBody))
|
||||||
} else {
|
} else {
|
||||||
r.debugLog.Printf("apiCall(): %v %v returned %v %s\n", request.Method, request.URL.String(), response.Status, oneLogLine(respBody))
|
r.debugLog("apiCall(): %v %v returned %v %s", request.Method, request.URL.String(), response.Status, oneLogLine(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
// step: check for a successfull response
|
// step: check for a successfull response
|
||||||
|
@ -311,7 +342,7 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
||||||
if response.StatusCode >= 500 && response.StatusCode <= 599 {
|
if response.StatusCode >= 500 && response.StatusCode <= 599 {
|
||||||
// step: mark the host as down
|
// step: mark the host as down
|
||||||
r.hosts.markDown(member)
|
r.hosts.markDown(member)
|
||||||
r.debugLog.Printf("apiCall(): request failed, host: %s, status: %d, trying another\n", member, response.StatusCode)
|
r.debugLog("apiCall(): request failed, host: %s, status: %d, trying another", member, response.StatusCode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,16 +360,28 @@ func (r *marathonClient) buildAPIRequest(method, path string, reader io.Reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the HTTP request to Marathon
|
// Build the HTTP request to Marathon
|
||||||
request, err = r.client.buildMarathonRequest(method, member, path, reader)
|
request, err = r.client.buildMarathonJSONRequest(method, member, path, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, member, newRequestError{err}
|
return nil, member, newRequestError{err}
|
||||||
}
|
}
|
||||||
return request, member, nil
|
return request, member, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildMarathonJSONRequest is like buildMarathonRequest but sets the
|
||||||
|
// Content-Type and Accept headers to application/json.
|
||||||
|
func (rc *httpClient) buildMarathonJSONRequest(method, member, path string, reader io.Reader) (request *http.Request, err error) {
|
||||||
|
req, err := rc.buildMarathonRequest(method, member, path, reader)
|
||||||
|
if err == nil {
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.Header.Add("Accept", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
// buildMarathonRequest creates a new HTTP request and configures it according to the *httpClient configuration.
|
// buildMarathonRequest creates a new HTTP request and configures it according to the *httpClient configuration.
|
||||||
// The path must not contain a leading "/", otherwise buildMarathonRequest will panic.
|
// The path must not contain a leading "/", otherwise buildMarathonRequest will panic.
|
||||||
func (rc *httpClient) buildMarathonRequest(method string, member string, path string, reader io.Reader) (request *http.Request, err error) {
|
func (rc *httpClient) buildMarathonRequest(method, member, path string, reader io.Reader) (request *http.Request, err error) {
|
||||||
if strings.HasPrefix(path, "/") {
|
if strings.HasPrefix(path, "/") {
|
||||||
panic(fmt.Sprintf("Path '%s' must not start with a leading slash", path))
|
panic(fmt.Sprintf("Path '%s' must not start with a leading slash", path))
|
||||||
}
|
}
|
||||||
|
@ -361,9 +404,6 @@ func (rc *httpClient) buildMarathonRequest(method string, member string, path st
|
||||||
request.Header.Add("Authorization", "token="+rc.config.DCOSToken)
|
request.Header.Add("Authorization", "token="+rc.config.DCOSToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
request.Header.Add("Content-Type", "application/json")
|
|
||||||
request.Header.Add("Accept", "application/json")
|
|
||||||
|
|
||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
vendor/github.com/gambol99/go-marathon/cluster.go
generated
vendored
19
vendor/github.com/gambol99/go-marathon/cluster.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -39,6 +39,9 @@ type cluster struct {
|
||||||
members []*member
|
members []*member
|
||||||
// the marathon HTTP client to ensure consistency in requests
|
// the marathon HTTP client to ensure consistency in requests
|
||||||
client *httpClient
|
client *httpClient
|
||||||
|
// healthCheckInterval is the interval by which we probe down nodes for
|
||||||
|
// availability again.
|
||||||
|
healthCheckInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// member represents an individual endpoint
|
// member represents an individual endpoint
|
||||||
|
@ -96,6 +99,7 @@ func newCluster(client *httpClient, marathonURL string, isDCOS bool) (*cluster,
|
||||||
return &cluster{
|
return &cluster{
|
||||||
client: client,
|
client: client,
|
||||||
members: members,
|
members: members,
|
||||||
|
healthCheckInterval: 5 * time.Second,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,20 +134,21 @@ func (c *cluster) markDown(endpoint string) {
|
||||||
// healthCheckNode performs a health check on the node and when active updates the status
|
// healthCheckNode performs a health check on the node and when active updates the status
|
||||||
func (c *cluster) healthCheckNode(node *member) {
|
func (c *cluster) healthCheckNode(node *member) {
|
||||||
// step: wait for the node to become active ... we are assuming a /ping is enough here
|
// step: wait for the node to become active ... we are assuming a /ping is enough here
|
||||||
for {
|
ticker := time.NewTicker(c.healthCheckInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for range ticker.C {
|
||||||
req, err := c.client.buildMarathonRequest("GET", node.endpoint, "ping", nil)
|
req, err := c.client.buildMarathonRequest("GET", node.endpoint, "ping", nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res, err := c.client.Do(req)
|
res, err := c.client.Do(req)
|
||||||
if err == nil && res.StatusCode == 200 {
|
if err == nil && res.StatusCode == 200 {
|
||||||
|
// step: mark the node as active again
|
||||||
|
c.Lock()
|
||||||
|
node.status = memberStatusUp
|
||||||
|
c.Unlock()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<-time.After(time.Duration(5 * time.Second))
|
|
||||||
}
|
}
|
||||||
// step: mark the node as active again
|
|
||||||
c.Lock()
|
|
||||||
defer c.Unlock()
|
|
||||||
node.status = memberStatusUp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// activeMembers returns a list of active members
|
// activeMembers returns a list of active members
|
||||||
|
|
6
vendor/github.com/gambol99/go-marathon/config.go
generated
vendored
6
vendor/github.com/gambol99/go-marathon/config.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -50,8 +50,10 @@ type Config struct {
|
||||||
DCOSToken string
|
DCOSToken string
|
||||||
// LogOutput the output for debug log messages
|
// LogOutput the output for debug log messages
|
||||||
LogOutput io.Writer
|
LogOutput io.Writer
|
||||||
// HTTPClient is the http client
|
// HTTPClient is the HTTP client
|
||||||
HTTPClient *http.Client
|
HTTPClient *http.Client
|
||||||
|
// HTTPSSEClient is the HTTP client used for SSE subscriptions, can't have client.Timeout set
|
||||||
|
HTTPSSEClient *http.Client
|
||||||
// wait time (in milliseconds) between repetitive requests to the API during polling
|
// wait time (in milliseconds) between repetitive requests to the API during polling
|
||||||
PollingWaitTime time.Duration
|
PollingWaitTime time.Duration
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/const.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/const.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/deployment.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/deployment.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
76
vendor/github.com/gambol99/go-marathon/docker.go
generated
vendored
76
vendor/github.com/gambol99/go-marathon/docker.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -50,6 +50,67 @@ type Volume struct {
|
||||||
HostPath string `json:"hostPath,omitempty"`
|
HostPath string `json:"hostPath,omitempty"`
|
||||||
External *ExternalVolume `json:"external,omitempty"`
|
External *ExternalVolume `json:"external,omitempty"`
|
||||||
Mode string `json:"mode,omitempty"`
|
Mode string `json:"mode,omitempty"`
|
||||||
|
Persistent *PersistentVolume `json:"persistent,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PersistentVolumeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PersistentVolumeTypeRoot PersistentVolumeType = "root"
|
||||||
|
PersistentVolumeTypePath PersistentVolumeType = "path"
|
||||||
|
PersistentVolumeTypeMount PersistentVolumeType = "mount"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PersistentVolume declares a Volume to be Persistent, and sets
|
||||||
|
// the size (in MiB) and optional type, max size (MiB) and constraints for the Volume.
|
||||||
|
type PersistentVolume struct {
|
||||||
|
Type PersistentVolumeType `json:"type,omitempty"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
MaxSize int `json:"maxSize,omitempty"`
|
||||||
|
Constraints *[][]string `json:"constraints,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetType sets the type of mesos disk resource to use
|
||||||
|
// type: PersistentVolumeType enum
|
||||||
|
func (p *PersistentVolume) SetType(tp PersistentVolumeType) *PersistentVolume {
|
||||||
|
p.Type = tp
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSize sets size of the persistent volume
|
||||||
|
// size: size in MiB
|
||||||
|
func (p *PersistentVolume) SetSize(size int) *PersistentVolume {
|
||||||
|
p.Size = size
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxSize sets maximum size of an exclusive mount-disk resource to consider;
|
||||||
|
// does not apply to root or path disk resource types
|
||||||
|
// maxSize: size in MiB
|
||||||
|
func (p *PersistentVolume) SetMaxSize(maxSize int) *PersistentVolume {
|
||||||
|
p.MaxSize = maxSize
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddConstraint adds a new constraint
|
||||||
|
// constraints: the constraint definition, one constraint per array element
|
||||||
|
func (p *PersistentVolume) AddConstraint(constraints ...string) *PersistentVolume {
|
||||||
|
if p.Constraints == nil {
|
||||||
|
p.EmptyConstraints()
|
||||||
|
}
|
||||||
|
|
||||||
|
c := *p.Constraints
|
||||||
|
c = append(c, constraints)
|
||||||
|
p.Constraints = &c
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyConstraints explicitly empties constraints -- use this if you need to empty
|
||||||
|
// constraints of an application that already has constraints set (setting constraints to nil will
|
||||||
|
// keep the current value)
|
||||||
|
func (p *PersistentVolume) EmptyConstraints() *PersistentVolume {
|
||||||
|
p.Constraints = &[][]string{}
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExternalVolume is an external volume definition
|
// ExternalVolume is an external volume definition
|
||||||
|
@ -98,6 +159,19 @@ func (container *Container) EmptyVolumes() *Container {
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPersistentVolume defines persistent properties for volume
|
||||||
|
func (v *Volume) SetPersistentVolume() *PersistentVolume {
|
||||||
|
ev := &PersistentVolume{}
|
||||||
|
v.Persistent = ev
|
||||||
|
return ev
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyPersistentVolume empties the persistent volume definition
|
||||||
|
func (v *Volume) EmptyPersistentVolume() *Volume {
|
||||||
|
v.Persistent = &PersistentVolume{}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// SetExternalVolume define external elements for a volume
|
// SetExternalVolume define external elements for a volume
|
||||||
// name: the name of the volume
|
// name: the name of the volume
|
||||||
// provider: the provider of the volume (e.g. dvdi)
|
// provider: the provider of the volume (e.g. dvdi)
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/error.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/error.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015 Rohith All rights reserved.
|
Copyright 2015 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/events.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/events.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
4
vendor/github.com/gambol99/go-marathon/group.go
generated
vendored
4
vendor/github.com/gambol99/go-marathon/group.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -136,7 +136,7 @@ func (r *marathonClient) GroupBy(name string, opts *GetGroupOpts) (*Group, error
|
||||||
// name: the identifier for the group
|
// name: the identifier for the group
|
||||||
func (r *marathonClient) HasGroup(name string) (bool, error) {
|
func (r *marathonClient) HasGroup(name string) (bool, error) {
|
||||||
path := fmt.Sprintf("%s/%s", marathonAPIGroups, trimRootPath(name))
|
path := fmt.Sprintf("%s/%s", marathonAPIGroups, trimRootPath(name))
|
||||||
err := r.apiCall("GET", path, "", nil)
|
err := r.apiGet(path, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apiErr, ok := err.(*APIError); ok && apiErr.ErrCode == ErrCodeNotFound {
|
if apiErr, ok := err.(*APIError); ok && apiErr.ErrCode == ErrCodeNotFound {
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
14
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
14
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -31,37 +31,37 @@ type HealthCheck struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCommand sets the given command on the health check.
|
// SetCommand sets the given command on the health check.
|
||||||
func (h HealthCheck) SetCommand(c Command) HealthCheck {
|
func (h *HealthCheck) SetCommand(c Command) *HealthCheck {
|
||||||
h.Command = &c
|
h.Command = &c
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPortIndex sets the given port index on the health check.
|
// SetPortIndex sets the given port index on the health check.
|
||||||
func (h HealthCheck) SetPortIndex(i int) HealthCheck {
|
func (h *HealthCheck) SetPortIndex(i int) *HealthCheck {
|
||||||
h.PortIndex = &i
|
h.PortIndex = &i
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPort sets the given port on the health check.
|
// SetPort sets the given port on the health check.
|
||||||
func (h HealthCheck) SetPort(i int) HealthCheck {
|
func (h *HealthCheck) SetPort(i int) *HealthCheck {
|
||||||
h.Port = &i
|
h.Port = &i
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPath sets the given path on the health check.
|
// SetPath sets the given path on the health check.
|
||||||
func (h HealthCheck) SetPath(p string) HealthCheck {
|
func (h *HealthCheck) SetPath(p string) *HealthCheck {
|
||||||
h.Path = &p
|
h.Path = &p
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMaxConsecutiveFailures sets the maximum consecutive failures on the health check.
|
// SetMaxConsecutiveFailures sets the maximum consecutive failures on the health check.
|
||||||
func (h HealthCheck) SetMaxConsecutiveFailures(i int) HealthCheck {
|
func (h *HealthCheck) SetMaxConsecutiveFailures(i int) *HealthCheck {
|
||||||
h.MaxConsecutiveFailures = &i
|
h.MaxConsecutiveFailures = &i
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetIgnoreHTTP1xx sets ignore http 1xx on the health check.
|
// SetIgnoreHTTP1xx sets ignore http 1xx on the health check.
|
||||||
func (h HealthCheck) SetIgnoreHTTP1xx(ignore bool) HealthCheck {
|
func (h *HealthCheck) SetIgnoreHTTP1xx(ignore bool) *HealthCheck {
|
||||||
h.IgnoreHTTP1xx = &ignore
|
h.IgnoreHTTP1xx = &ignore
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/info.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/info.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/last_task_failure.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/last_task_failure.go
generated
vendored
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright 2015 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -20,6 +21,7 @@ type LastTaskFailure struct {
|
||||||
AppID string `json:"appId,omitempty"`
|
AppID string `json:"appId,omitempty"`
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
|
SlaveID string `json:"slaveId,omitempty"`
|
||||||
State string `json:"state,omitempty"`
|
State string `json:"state,omitempty"`
|
||||||
TaskID string `json:"taskId,omitempty"`
|
TaskID string `json:"taskId,omitempty"`
|
||||||
Timestamp string `json:"timestamp,omitempty"`
|
Timestamp string `json:"timestamp,omitempty"`
|
||||||
|
|
30
vendor/github.com/gambol99/go-marathon/port_definition.go
generated
vendored
30
vendor/github.com/gambol99/go-marathon/port_definition.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 Rohith All rights reserved.
|
Copyright 2016 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -27,15 +27,39 @@ type PortDefinition struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPort sets the given port for the PortDefinition
|
// SetPort sets the given port for the PortDefinition
|
||||||
func (p PortDefinition) SetPort(port int) PortDefinition {
|
func (p *PortDefinition) SetPort(port int) *PortDefinition {
|
||||||
|
if p.Port == nil {
|
||||||
|
p.EmptyPort()
|
||||||
|
}
|
||||||
p.Port = &port
|
p.Port = &port
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmptyPort sets the port to 0 for the PortDefinition
|
||||||
|
func (p *PortDefinition) EmptyPort() *PortDefinition {
|
||||||
|
port := 0
|
||||||
|
p.Port = &port
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProtocol sets the protocol for the PortDefinition
|
||||||
|
// protocol: the protocol as a string
|
||||||
|
func (p *PortDefinition) SetProtocol(protocol string) *PortDefinition {
|
||||||
|
p.Protocol = protocol
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetName sets the name for the PortDefinition
|
||||||
|
// name: the name of the PortDefinition
|
||||||
|
func (p *PortDefinition) SetName(name string) *PortDefinition {
|
||||||
|
p.Name = name
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// AddLabel adds a label to the PortDefinition
|
// AddLabel adds a label to the PortDefinition
|
||||||
// name: the name of the label
|
// name: the name of the label
|
||||||
// value: value for this label
|
// value: value for this label
|
||||||
func (p PortDefinition) AddLabel(name, value string) PortDefinition {
|
func (p *PortDefinition) AddLabel(name, value string) *PortDefinition {
|
||||||
if p.Labels == nil {
|
if p.Labels == nil {
|
||||||
p.EmptyLabels()
|
p.EmptyLabels()
|
||||||
}
|
}
|
||||||
|
|
8
vendor/github.com/gambol99/go-marathon/queue.go
generated
vendored
8
vendor/github.com/gambol99/go-marathon/queue.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 Rohith All rights reserved.
|
Copyright 2016 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -52,9 +52,5 @@ func (r *marathonClient) Queue() (*Queue, error) {
|
||||||
// appID: the ID of the application
|
// appID: the ID of the application
|
||||||
func (r *marathonClient) DeleteQueueDelay(appID string) error {
|
func (r *marathonClient) DeleteQueueDelay(appID string) error {
|
||||||
path := fmt.Sprintf("%s/%s/delay", marathonAPIQueue, trimRootPath(appID))
|
path := fmt.Sprintf("%s/%s/delay", marathonAPIQueue, trimRootPath(appID))
|
||||||
err := r.apiDelete(path, nil, nil)
|
return r.apiDelete(path, nil, nil)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/readiness.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/readiness.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Rohith All rights reserved.
|
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
48
vendor/github.com/gambol99/go-marathon/residency.go
generated
vendored
Normal file
48
vendor/github.com/gambol99/go-marathon/residency.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package marathon
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// TaskLostBehaviorType sets action taken when the resident task is lost
|
||||||
|
type TaskLostBehaviorType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TaskLostBehaviorTypeWaitForever indicates to not take any action when the resident task is lost
|
||||||
|
TaskLostBehaviorTypeWaitForever TaskLostBehaviorType = "WAIT_FOREVER"
|
||||||
|
// TaskLostBehaviorTypeWaitForever indicates to try relaunching the lost resident task on
|
||||||
|
// another node after the relaunch escalation timeout has elapsed
|
||||||
|
TaskLostBehaviorTypeRelaunchAfterTimeout TaskLostBehaviorType = "RELAUNCH_AFTER_TIMEOUT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Residency defines how terminal states of tasks with local persistent volumes are handled
|
||||||
|
type Residency struct {
|
||||||
|
TaskLostBehavior TaskLostBehaviorType `json:"taskLostBehavior,omitempty"`
|
||||||
|
RelaunchEscalationTimeoutSeconds int `json:"relaunchEscalationTimeoutSeconds,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTaskLostBehavior sets the residency behavior
|
||||||
|
func (r *Residency) SetTaskLostBehavior(behavior TaskLostBehaviorType) *Residency {
|
||||||
|
r.TaskLostBehavior = behavior
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRelaunchEscalationTimeout sets the residency relaunch escalation timeout with seconds precision
|
||||||
|
func (r *Residency) SetRelaunchEscalationTimeout(timeout time.Duration) *Residency {
|
||||||
|
r.RelaunchEscalationTimeoutSeconds = int(timeout.Seconds())
|
||||||
|
return r
|
||||||
|
}
|
38
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
38
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -103,8 +103,7 @@ func (r *marathonClient) registerSubscription() error {
|
||||||
case EventsTransportCallback:
|
case EventsTransportCallback:
|
||||||
return r.registerCallbackSubscription()
|
return r.registerCallbackSubscription()
|
||||||
case EventsTransportSSE:
|
case EventsTransportSSE:
|
||||||
r.registerSSESubscription()
|
return r.registerSSESubscription()
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("the events transport: %d is not supported", r.config.EventsTransport)
|
return fmt.Errorf("the events transport: %d is not supported", r.config.EventsTransport)
|
||||||
}
|
}
|
||||||
|
@ -167,27 +166,34 @@ func (r *marathonClient) registerCallbackSubscription() error {
|
||||||
// connect to the SSE stream and to process the received events. To establish
|
// connect to the SSE stream and to process the received events. To establish
|
||||||
// the connection it tries the active cluster members until no more member is
|
// the connection it tries the active cluster members until no more member is
|
||||||
// active. When this happens it will retry to get a connection every 5 seconds.
|
// active. When this happens it will retry to get a connection every 5 seconds.
|
||||||
func (r *marathonClient) registerSSESubscription() {
|
func (r *marathonClient) registerSSESubscription() error {
|
||||||
if r.subscribedToSSE {
|
if r.subscribedToSSE {
|
||||||
return
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.config.HTTPSSEClient.Timeout != 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"global timeout must not be set for SSE connections (found %s) -- remove global timeout from HTTP client or provide separate SSE HTTP client without global timeout",
|
||||||
|
r.config.HTTPSSEClient.Timeout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
stream, err := r.connectToSSE()
|
stream, err := r.connectToSSE()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.debugLog.Printf("Error connecting SSE subscription: %s", err)
|
r.debugLog("Error connecting SSE subscription: %s", err)
|
||||||
<-time.After(5 * time.Second)
|
<-time.After(5 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.listenToSSE(stream)
|
err = r.listenToSSE(stream)
|
||||||
stream.Close()
|
stream.Close()
|
||||||
r.debugLog.Printf("Error on SSE subscription: %s", err)
|
r.debugLog("Error on SSE subscription: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.subscribedToSSE = true
|
r.subscribedToSSE = true
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// connectToSSE tries to establish an *eventsource.Stream to any of the Marathon cluster members, marking the
|
// connectToSSE tries to establish an *eventsource.Stream to any of the Marathon cluster members, marking the
|
||||||
|
@ -209,15 +215,15 @@ func (r *marathonClient) connectToSSE() (*eventsource.Stream, error) {
|
||||||
// its underlying fields for performance reasons. See note that at least the Transport
|
// its underlying fields for performance reasons. See note that at least the Transport
|
||||||
// should be reused here: https://golang.org/pkg/net/http/#Client
|
// should be reused here: https://golang.org/pkg/net/http/#Client
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
Transport: r.config.HTTPClient.Transport,
|
Transport: r.config.HTTPSSEClient.Transport,
|
||||||
CheckRedirect: r.config.HTTPClient.CheckRedirect,
|
CheckRedirect: r.config.HTTPSSEClient.CheckRedirect,
|
||||||
Jar: r.config.HTTPClient.Jar,
|
Jar: r.config.HTTPSSEClient.Jar,
|
||||||
Timeout: r.config.HTTPClient.Timeout,
|
Timeout: r.config.HTTPSSEClient.Timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := eventsource.SubscribeWith("", httpClient, request)
|
stream, err := eventsource.SubscribeWith("", httpClient, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.debugLog.Printf("Error subscribing to Marathon event stream: %s", err)
|
r.debugLog("Error subscribing to Marathon event stream: %s", err)
|
||||||
r.hosts.markDown(member)
|
r.hosts.markDown(member)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -231,7 +237,7 @@ func (r *marathonClient) listenToSSE(stream *eventsource.Stream) error {
|
||||||
select {
|
select {
|
||||||
case ev := <-stream.Events:
|
case ev := <-stream.Events:
|
||||||
if err := r.handleEvent(ev.Data()); err != nil {
|
if err := r.handleEvent(ev.Data()); err != nil {
|
||||||
r.debugLog.Printf("listenToSSE(): failed to handle event: %v", err)
|
r.debugLog("listenToSSE(): failed to handle event: %v", err)
|
||||||
}
|
}
|
||||||
case err := <-stream.Errors:
|
case err := <-stream.Errors:
|
||||||
return err
|
return err
|
||||||
|
@ -319,12 +325,12 @@ func (r *marathonClient) handleCallbackEvent(writer http.ResponseWriter, request
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO should this return a 500?
|
// TODO should this return a 500?
|
||||||
r.debugLog.Printf("handleCallbackEvent(): failed to read request body, error: %s\n", err)
|
r.debugLog("handleCallbackEvent(): failed to read request body, error: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.handleEvent(string(body[:])); err != nil {
|
if err := r.handleEvent(string(body[:])); err != nil {
|
||||||
// TODO should this return a 500?
|
// TODO should this return a 500?
|
||||||
r.debugLog.Printf("handleCallbackEvent(): failed to handle event: %v\n", err)
|
r.debugLog("handleCallbackEvent(): failed to handle event: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
vendor/github.com/gambol99/go-marathon/task.go
generated
vendored
4
vendor/github.com/gambol99/go-marathon/task.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -217,7 +217,7 @@ func (r *Task) allHealthChecksAlive() bool {
|
||||||
}
|
}
|
||||||
// step: check the health results then
|
// step: check the health results then
|
||||||
for _, check := range r.HealthCheckResults {
|
for _, check := range r.HealthCheckResults {
|
||||||
if check.Alive == false {
|
if !check.Alive {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
6
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2017 Rohith All rights reserved.
|
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -65,13 +65,13 @@ func (us *UnreachableStrategy) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInactiveAfterSeconds sets the period after which instance will be marked as inactive.
|
// SetInactiveAfterSeconds sets the period after which instance will be marked as inactive.
|
||||||
func (us UnreachableStrategy) SetInactiveAfterSeconds(cap float64) UnreachableStrategy {
|
func (us *UnreachableStrategy) SetInactiveAfterSeconds(cap float64) *UnreachableStrategy {
|
||||||
us.InactiveAfterSeconds = &cap
|
us.InactiveAfterSeconds = &cap
|
||||||
return us
|
return us
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpungeAfterSeconds sets the period after which instance will be expunged.
|
// SetExpungeAfterSeconds sets the period after which instance will be expunged.
|
||||||
func (us UnreachableStrategy) SetExpungeAfterSeconds(cap float64) UnreachableStrategy {
|
func (us *UnreachableStrategy) SetExpungeAfterSeconds(cap float64) *UnreachableStrategy {
|
||||||
us.ExpungeAfterSeconds = &cap
|
us.ExpungeAfterSeconds = &cap
|
||||||
return us
|
return us
|
||||||
}
|
}
|
||||||
|
|
6
vendor/github.com/gambol99/go-marathon/upgrade_strategy.go
generated
vendored
6
vendor/github.com/gambol99/go-marathon/upgrade_strategy.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -23,13 +23,13 @@ type UpgradeStrategy struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMinimumHealthCapacity sets the minimum health capacity.
|
// SetMinimumHealthCapacity sets the minimum health capacity.
|
||||||
func (us UpgradeStrategy) SetMinimumHealthCapacity(cap float64) UpgradeStrategy {
|
func (us *UpgradeStrategy) SetMinimumHealthCapacity(cap float64) *UpgradeStrategy {
|
||||||
us.MinimumHealthCapacity = &cap
|
us.MinimumHealthCapacity = &cap
|
||||||
return us
|
return us
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMaximumOverCapacity sets the maximum over capacity.
|
// SetMaximumOverCapacity sets the maximum over capacity.
|
||||||
func (us UpgradeStrategy) SetMaximumOverCapacity(cap float64) UpgradeStrategy {
|
func (us *UpgradeStrategy) SetMaximumOverCapacity(cap float64) *UpgradeStrategy {
|
||||||
us.MaximumOverCapacity = &cap
|
us.MaximumOverCapacity = &cap
|
||||||
return us
|
return us
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/utils.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/utils.go
generated
vendored
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2014 Rohith All rights reserved.
|
Copyright 2014 The go-marathon Authors All rights reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
Loading…
Reference in a new issue