Vendor integration dependencies.
This commit is contained in:
parent
dd5e3fba01
commit
55b57c736b
2451 changed files with 731611 additions and 0 deletions
202
integration/vendor/github.com/mesosphere/mesos-dns/LICENSE
generated
vendored
Normal file
202
integration/vendor/github.com/mesosphere/mesos-dns/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Mesosphere
|
||||
|
||||
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.
|
||||
|
115
integration/vendor/github.com/mesosphere/mesos-dns/detect/masters.go
generated
vendored
Normal file
115
integration/vendor/github.com/mesosphere/mesos-dns/detect/masters.go
generated
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
package detect
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
|
||||
"github.com/mesosphere/mesos-dns/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
_ detector.MasterChanged = (*Masters)(nil)
|
||||
_ detector.AllMasters = (*Masters)(nil)
|
||||
)
|
||||
|
||||
// Masters detects changes of leader and/or master elections
|
||||
// and sends these changes to a channel.
|
||||
type Masters struct {
|
||||
// current masters list,
|
||||
// 1st item represents the leader,
|
||||
// the rest remaining masters
|
||||
masters []string
|
||||
|
||||
// the channel leader/master changes are being sent to
|
||||
changed chan<- []string
|
||||
}
|
||||
|
||||
// NewMasters returns a new Masters detector with the given initial masters
|
||||
// and the given changed channel to which master changes will be sent to.
|
||||
// Initially the leader is unknown which is represented by
|
||||
// setting the first item of the sent masters slice to be empty.
|
||||
func NewMasters(masters []string, changed chan<- []string) *Masters {
|
||||
return &Masters{
|
||||
masters: append([]string{""}, masters...),
|
||||
changed: changed,
|
||||
}
|
||||
}
|
||||
|
||||
// OnMasterChanged sets the given MasterInfo as the current leader
|
||||
// leaving the remaining masters unchanged and emits the current masters state.
|
||||
// It implements the detector.MasterChanged interface.
|
||||
func (ms *Masters) OnMasterChanged(leader *mesos.MasterInfo) {
|
||||
logging.VeryVerbose.Println("Updated leader: ", leader)
|
||||
ms.masters = ordered(masterAddr(leader), ms.masters[1:])
|
||||
emit(ms.changed, ms.masters)
|
||||
}
|
||||
|
||||
// UpdatedMasters sets the given slice of MasterInfo as the current remaining masters
|
||||
// leaving the current leader unchanged and emits the current masters state.
|
||||
// It implements the detector.AllMasters interface.
|
||||
func (ms *Masters) UpdatedMasters(infos []*mesos.MasterInfo) {
|
||||
logging.VeryVerbose.Println("Updated masters: ", infos)
|
||||
masters := make([]string, 0, len(infos))
|
||||
for _, info := range infos {
|
||||
if addr := masterAddr(info); addr != "" {
|
||||
masters = append(masters, addr)
|
||||
}
|
||||
}
|
||||
ms.masters = ordered(ms.masters[0], masters)
|
||||
emit(ms.changed, ms.masters)
|
||||
}
|
||||
|
||||
func emit(ch chan<- []string, s []string) {
|
||||
ch <- append(make([]string, 0, len(s)), s...)
|
||||
}
|
||||
|
||||
// ordered returns a slice of masters with the given leader in the first position
|
||||
func ordered(leader string, masters []string) []string {
|
||||
ms := append(make([]string, 0, len(masters)+1), leader)
|
||||
for _, m := range masters {
|
||||
if m != leader {
|
||||
ms = append(ms, m)
|
||||
}
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
// masterAddr returns an address (ip:port) from the given *mesos.MasterInfo or
|
||||
// an empty string if it nil.
|
||||
//
|
||||
// BUG(tsenart): The byte order of the `ip` field in MasterInfo is platform
|
||||
// dependent. We assume that Mesos is compiled with the same architecture as
|
||||
// Mesos-DNS and hence same byte order. If this isn't the case, the address
|
||||
// returned will be wrong. This only affects Mesos versions < 0.24.0
|
||||
func masterAddr(info *mesos.MasterInfo) string {
|
||||
if info == nil {
|
||||
return ""
|
||||
}
|
||||
ip, port := "", int64(0)
|
||||
if addr := info.GetAddress(); addr != nil { // Mesos >= 0.24.0
|
||||
ip, port = addr.GetIp(), int64(addr.GetPort())
|
||||
} else { // Mesos < 0.24.0
|
||||
ipv4 := make([]byte, net.IPv4len)
|
||||
byteOrder.PutUint32(ipv4, info.GetIp())
|
||||
ip, port = net.IP(ipv4).String(), int64(info.GetPort())
|
||||
}
|
||||
return net.JoinHostPort(ip, strconv.FormatInt(port, 10))
|
||||
}
|
||||
|
||||
// byteOrder is instantiated at package initialization time to the
|
||||
// binary.ByteOrder of the running process.
|
||||
// https://groups.google.com/d/msg/golang-nuts/zmh64YkqOV8/iJe-TrTTeREJ
|
||||
var byteOrder = func() binary.ByteOrder {
|
||||
switch x := uint32(0x01020304); *(*byte)(unsafe.Pointer(&x)) {
|
||||
case 0x01:
|
||||
return binary.BigEndian
|
||||
case 0x04:
|
||||
return binary.LittleEndian
|
||||
}
|
||||
panic("unknown byte order")
|
||||
}()
|
12
integration/vendor/github.com/mesosphere/mesos-dns/errorutil/errorutil.go
generated
vendored
Normal file
12
integration/vendor/github.com/mesosphere/mesos-dns/errorutil/errorutil.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package errorutil
|
||||
|
||||
// ErrorFunction A function definition that returns an error
|
||||
// to be passed to the Ignore or Panic error handler
|
||||
type ErrorFunction func() error
|
||||
|
||||
// Ignore Calls an ErrorFunction, and ignores the result.
|
||||
// This allows us to be more explicit when there is no error
|
||||
// handling to be done, for example in defers
|
||||
func Ignore(f ErrorFunction) {
|
||||
_ = f()
|
||||
}
|
104
integration/vendor/github.com/mesosphere/mesos-dns/logging/logging.go
generated
vendored
Normal file
104
integration/vendor/github.com/mesosphere/mesos-dns/logging/logging.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
var (
|
||||
// VerboseFlag enables verbose logging if set to true.
|
||||
VerboseFlag bool
|
||||
// VeryVerboseFlag enables very verbose logging if set to true.
|
||||
VeryVerboseFlag bool
|
||||
// Verbose is this package's verbose Logger.
|
||||
Verbose *log.Logger
|
||||
// VeryVerbose is this package's very verbose Logger.
|
||||
VeryVerbose *log.Logger
|
||||
// Error is this package's error Logger.
|
||||
Error *log.Logger
|
||||
)
|
||||
|
||||
// Counter defines an interface for a monotonically incrementing value.
|
||||
type Counter interface {
|
||||
Inc()
|
||||
}
|
||||
|
||||
// LogCounter implements the Counter interface with a uint64 register.
|
||||
// It's safe for concurrent use.
|
||||
type LogCounter struct {
|
||||
value uint64
|
||||
}
|
||||
|
||||
// Inc increments the counter by one.
|
||||
func (lc *LogCounter) Inc() {
|
||||
atomic.AddUint64(&lc.value, 1)
|
||||
}
|
||||
|
||||
// String returns a string represention of the counter.
|
||||
func (lc *LogCounter) String() string {
|
||||
return strconv.FormatUint(atomic.LoadUint64(&lc.value), 10)
|
||||
}
|
||||
|
||||
// LogOut holds metrics captured in an instrumented runtime.
|
||||
type LogOut struct {
|
||||
MesosRequests Counter
|
||||
MesosSuccess Counter
|
||||
MesosNXDomain Counter
|
||||
MesosFailed Counter
|
||||
NonMesosRequests Counter
|
||||
NonMesosSuccess Counter
|
||||
NonMesosNXDomain Counter
|
||||
NonMesosFailed Counter
|
||||
NonMesosForwarded Counter
|
||||
}
|
||||
|
||||
// CurLog is the default package level LogOut.
|
||||
var CurLog = LogOut{
|
||||
MesosRequests: &LogCounter{},
|
||||
MesosSuccess: &LogCounter{},
|
||||
MesosNXDomain: &LogCounter{},
|
||||
MesosFailed: &LogCounter{},
|
||||
NonMesosRequests: &LogCounter{},
|
||||
NonMesosSuccess: &LogCounter{},
|
||||
NonMesosNXDomain: &LogCounter{},
|
||||
NonMesosFailed: &LogCounter{},
|
||||
NonMesosForwarded: &LogCounter{},
|
||||
}
|
||||
|
||||
// PrintCurLog prints out the current LogOut and then resets
|
||||
func PrintCurLog() {
|
||||
VeryVerbose.Printf("%+v\n", CurLog)
|
||||
}
|
||||
|
||||
// SetupLogs provides the following logs
|
||||
// Verbose = optional verbosity
|
||||
// VeryVerbose = optional verbosity
|
||||
// Error = stderr
|
||||
func SetupLogs() {
|
||||
// initialize logging flags
|
||||
if glog.V(2) {
|
||||
VeryVerboseFlag = true
|
||||
} else if glog.V(1) {
|
||||
VerboseFlag = true
|
||||
}
|
||||
|
||||
logopts := log.Ldate | log.Ltime | log.Lshortfile
|
||||
|
||||
if VerboseFlag {
|
||||
Verbose = log.New(os.Stdout, "VERBOSE: ", logopts)
|
||||
VeryVerbose = log.New(ioutil.Discard, "VERY VERBOSE: ", logopts)
|
||||
} else if VeryVerboseFlag {
|
||||
Verbose = log.New(os.Stdout, "VERY VERBOSE: ", logopts)
|
||||
VeryVerbose = Verbose
|
||||
} else {
|
||||
Verbose = log.New(ioutil.Discard, "VERBOSE: ", logopts)
|
||||
VeryVerbose = log.New(ioutil.Discard, "VERY VERBOSE: ", logopts)
|
||||
}
|
||||
|
||||
Error = log.New(os.Stderr, "ERROR: ", logopts)
|
||||
}
|
98
integration/vendor/github.com/mesosphere/mesos-dns/main.go
generated
vendored
Normal file
98
integration/vendor/github.com/mesosphere/mesos-dns/main.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
"github.com/mesosphere/mesos-dns/detect"
|
||||
"github.com/mesosphere/mesos-dns/logging"
|
||||
"github.com/mesosphere/mesos-dns/records"
|
||||
"github.com/mesosphere/mesos-dns/resolver"
|
||||
"github.com/mesosphere/mesos-dns/util"
|
||||
)
|
||||
|
||||
func main() {
|
||||
util.PanicHandlers = append(util.PanicHandlers, func(_ interface{}) {
|
||||
// by default the handler already logs the panic
|
||||
os.Exit(1)
|
||||
})
|
||||
|
||||
var versionFlag bool
|
||||
|
||||
// parse flags
|
||||
cjson := flag.String("config", "config.json", "path to config file (json)")
|
||||
flag.BoolVar(&versionFlag, "version", false, "output the version")
|
||||
flag.Parse()
|
||||
|
||||
// -version
|
||||
if versionFlag {
|
||||
fmt.Println(Version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// initialize logging
|
||||
logging.SetupLogs()
|
||||
|
||||
// initialize resolver
|
||||
config := records.SetConfig(*cjson)
|
||||
res := resolver.New(Version, config)
|
||||
errch := make(chan error)
|
||||
|
||||
// launch DNS server
|
||||
if config.DNSOn {
|
||||
go func() { errch <- <-res.LaunchDNS() }()
|
||||
}
|
||||
|
||||
// launch HTTP server
|
||||
if config.HTTPOn {
|
||||
go func() { errch <- <-res.LaunchHTTP() }()
|
||||
}
|
||||
|
||||
changed := detectMasters(config.Zk, config.Masters)
|
||||
reload := time.NewTicker(time.Second * time.Duration(config.RefreshSeconds))
|
||||
zkTimeout := time.Second * time.Duration(config.ZkDetectionTimeout)
|
||||
timeout := time.AfterFunc(zkTimeout, func() {
|
||||
if zkTimeout > 0 {
|
||||
errch <- fmt.Errorf("master detection timed out after %s", zkTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
defer reload.Stop()
|
||||
defer util.HandleCrash()
|
||||
for {
|
||||
select {
|
||||
case <-reload.C:
|
||||
res.Reload()
|
||||
case masters := <-changed:
|
||||
if len(masters) == 0 || masters[0] == "" { // no leader
|
||||
timeout.Reset(zkTimeout)
|
||||
} else {
|
||||
timeout.Stop()
|
||||
}
|
||||
logging.VeryVerbose.Printf("new masters detected: %v", masters)
|
||||
res.SetMasters(masters)
|
||||
res.Reload()
|
||||
case err := <-errch:
|
||||
logging.Error.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func detectMasters(zk string, masters []string) <-chan []string {
|
||||
changed := make(chan []string, 1)
|
||||
if zk != "" {
|
||||
logging.Verbose.Println("Starting master detector for ZK ", zk)
|
||||
if md, err := detector.New(zk); err != nil {
|
||||
log.Fatalf("failed to create master detector: %v", err)
|
||||
} else if err := md.Detect(detect.NewMasters(masters, changed)); err != nil {
|
||||
log.Fatalf("failed to initialize master detector: %v", err)
|
||||
}
|
||||
} else {
|
||||
changed <- masters
|
||||
}
|
||||
return changed
|
||||
}
|
26
integration/vendor/github.com/mesosphere/mesos-dns/models/models.go
generated
vendored
Normal file
26
integration/vendor/github.com/mesosphere/mesos-dns/models/models.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package models
|
||||
|
||||
// AXFRResourceRecordSet is a representation of record name -> string
|
||||
type AXFRResourceRecordSet map[string][]string
|
||||
|
||||
// Even though it would be nice to have the model map to something better than a string
|
||||
// (a la an actual SRV, or A struct).
|
||||
// This is the internal structure of how mesos-dns works today and the transformation of string -> DNS Struct
|
||||
// happens on actual query time. Why this logic happens at query time? Who knows.
|
||||
|
||||
// AXFRRecords are the As, and SRVs that actually make up the Mesos-DNS zone
|
||||
type AXFRRecords struct {
|
||||
As AXFRResourceRecordSet
|
||||
SRVs AXFRResourceRecordSet
|
||||
}
|
||||
|
||||
// AXFR is a rough representation of a "transfer" of the Mesos-DNS data
|
||||
type AXFR struct {
|
||||
TTL int32 // DNS TTL according to config
|
||||
Serial uint32 // Current DNS zone version / serial number
|
||||
RefreshSeconds int // How often we try to poll Mesos for updates -- minimum downstream poll interval
|
||||
Mname string // primary name server
|
||||
Rname string // email of admin esponsible
|
||||
Domain string // Domain: name of the domain used (default "mesos", ie .mesos domain)
|
||||
Records AXFRRecords
|
||||
}
|
80
integration/vendor/github.com/mesosphere/mesos-dns/records/chains.go
generated
vendored
Normal file
80
integration/vendor/github.com/mesosphere/mesos-dns/records/chains.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"github.com/mesosphere/mesos-dns/records/labels"
|
||||
)
|
||||
|
||||
// chain is a generation func that consumes record-like strings and does
|
||||
// something with them
|
||||
type chain func(...string)
|
||||
|
||||
const (
|
||||
protocolNone = "" // for readability
|
||||
domainNone = "" // for readability
|
||||
)
|
||||
|
||||
// withProtocol appends `._{protocol}.{framework}` to records. if protocol is "" then
|
||||
// the protocols "tcp" and "udp" are assumed.
|
||||
func withProtocol(protocol, framework string, spec labels.Func, gen chain) chain {
|
||||
return func(records ...string) {
|
||||
protocol = spec(protocol)
|
||||
if protocol != protocolNone {
|
||||
for i := range records {
|
||||
records[i] += "._" + protocol + "." + framework
|
||||
}
|
||||
} else {
|
||||
records = append(records, records...)
|
||||
for i, j := 0, len(records)/2; j < len(records); {
|
||||
records[i] += "._tcp." + framework
|
||||
records[j] += "._udp." + framework
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
gen(records...)
|
||||
}
|
||||
}
|
||||
|
||||
// withSubdomains appends `.{subdomain}` (for each subdomain spec'd) to records.
|
||||
// the empty subdomain "" indicates to generate records w/o a subdomain fragment.
|
||||
func withSubdomains(subdomains []string, gen chain) chain {
|
||||
if len(subdomains) == 0 {
|
||||
return gen
|
||||
}
|
||||
return func(records ...string) {
|
||||
var (
|
||||
recordLen = len(records)
|
||||
tmp = make([]string, recordLen*len(subdomains))
|
||||
offset = 0
|
||||
)
|
||||
for s := range subdomains {
|
||||
if subdomains[s] == domainNone {
|
||||
copy(tmp[offset:], records)
|
||||
} else {
|
||||
for i := range records {
|
||||
tmp[offset+i] = records[i] + "." + subdomains[s]
|
||||
}
|
||||
}
|
||||
offset += recordLen
|
||||
}
|
||||
gen(tmp...)
|
||||
}
|
||||
}
|
||||
|
||||
// withNamedPort prepends a `_{discoveryInfo port name}.` to records
|
||||
func withNamedPort(portName string, spec labels.Func, gen chain) chain {
|
||||
portName = spec(portName)
|
||||
if portName == "" {
|
||||
return gen
|
||||
}
|
||||
return func(records ...string) {
|
||||
// generate without port-name prefix
|
||||
gen(records...)
|
||||
|
||||
// generate with port-name prefix
|
||||
for i := range records {
|
||||
records[i] = "_" + portName + "." + records[i]
|
||||
}
|
||||
gen(records...)
|
||||
}
|
||||
}
|
261
integration/vendor/github.com/mesosphere/mesos-dns/records/config.go
generated
vendored
Normal file
261
integration/vendor/github.com/mesosphere/mesos-dns/records/config.go
generated
vendored
Normal file
|
@ -0,0 +1,261 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mesosphere/mesos-dns/logging"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Config holds mesos dns configuration
|
||||
type Config struct {
|
||||
// Refresh frequency: the frequency in seconds of regenerating records (default 60)
|
||||
RefreshSeconds int
|
||||
// Resolver port: port used to listen for slave requests (default 53)
|
||||
Port int
|
||||
// Timeout is the default connect/read/write timeout for outbound
|
||||
// queries
|
||||
Timeout int
|
||||
// Timeout in seconds waiting for the master to return data from StateJson
|
||||
StateTimeoutSeconds int
|
||||
// Zookeeper Detection Timeout: how long in seconds to wait for Zookeeper to
|
||||
// be initially responsive. Default is 30 and 0 means no timeout.
|
||||
ZkDetectionTimeout int
|
||||
// NOTE(tsenart): HTTPPort, DNSOn and HTTPOn have defined JSON keys for
|
||||
// backwards compatibility with external API clients.
|
||||
HTTPPort int `json:"HttpPort"`
|
||||
// TTL: the TTL value used for SRV and A records (default 60)
|
||||
TTL int32
|
||||
// SOA record fields (see http://tools.ietf.org/html/rfc1035#page-18)
|
||||
SOASerial uint32 // initial version number (incremented on refresh)
|
||||
SOARefresh uint32 // refresh interval
|
||||
SOARetry uint32 // retry interval
|
||||
SOAExpire uint32 // expiration time
|
||||
SOAMinttl uint32 // minimum TTL
|
||||
SOAMname string // primary name server
|
||||
SOARname string // email of admin esponsible
|
||||
// Mesos master(s): a list of IP:port pairs for one or more Mesos masters
|
||||
Masters []string
|
||||
// DNS server: IP address of the DNS server for forwarded accesses
|
||||
Resolvers []string
|
||||
// IPSources is the prioritized list of task IP sources
|
||||
IPSources []string // e.g. ["host", "docker", "mesos", "rkt"]
|
||||
// Zookeeper: a single Zk url
|
||||
Zk string
|
||||
// Domain: name of the domain used (default "mesos", ie .mesos domain)
|
||||
Domain string
|
||||
// File is the location of the config.json file
|
||||
File string
|
||||
// Listen is the server DNS listener IP address
|
||||
Listener string
|
||||
// HTTPListen is the server HTTP listener IP address
|
||||
HTTPListener string
|
||||
// Value of RecursionAvailable for responses in Mesos domain
|
||||
RecurseOn bool
|
||||
// Enable serving DSN and HTTP requests
|
||||
DNSOn bool `json:"DnsOn"`
|
||||
HTTPOn bool `json:"HttpOn"`
|
||||
// Enable replies for external requests
|
||||
ExternalOn bool
|
||||
// EnforceRFC952 will enforce an older, more strict set of rules for DNS labels
|
||||
EnforceRFC952 bool
|
||||
// Enumeration enabled via the API enumeration endpoint
|
||||
EnumerationOn bool
|
||||
}
|
||||
|
||||
// NewConfig return the default config of the resolver
|
||||
func NewConfig() Config {
|
||||
return Config{
|
||||
ZkDetectionTimeout: 30,
|
||||
RefreshSeconds: 60,
|
||||
TTL: 60,
|
||||
Domain: "mesos",
|
||||
Port: 53,
|
||||
Timeout: 5,
|
||||
StateTimeoutSeconds: 300,
|
||||
SOARname: "root.ns1.mesos",
|
||||
SOAMname: "ns1.mesos",
|
||||
SOARefresh: 60,
|
||||
SOARetry: 600,
|
||||
SOAExpire: 86400,
|
||||
SOAMinttl: 60,
|
||||
Resolvers: []string{"8.8.8.8"},
|
||||
Listener: "0.0.0.0",
|
||||
HTTPListener: "0.0.0.0",
|
||||
HTTPPort: 8123,
|
||||
DNSOn: true,
|
||||
HTTPOn: true,
|
||||
ExternalOn: true,
|
||||
RecurseOn: true,
|
||||
IPSources: []string{"netinfo", "mesos", "host"},
|
||||
EnumerationOn: true,
|
||||
}
|
||||
}
|
||||
|
||||
// SetConfig instantiates a Config struct read in from config.json
|
||||
func SetConfig(cjson string) Config {
|
||||
c, err := readConfig(cjson)
|
||||
if err != nil {
|
||||
logging.Error.Fatal(err)
|
||||
}
|
||||
logging.Verbose.Printf("config loaded from %q", c.File)
|
||||
// validate and complete configuration file
|
||||
err = validateEnabledServices(c)
|
||||
if err != nil {
|
||||
logging.Error.Fatalf("service validation failed: %v", err)
|
||||
}
|
||||
if err = validateMasters(c.Masters); err != nil {
|
||||
logging.Error.Fatalf("Masters validation failed: %v", err)
|
||||
}
|
||||
|
||||
if c.ExternalOn {
|
||||
if len(c.Resolvers) == 0 {
|
||||
c.Resolvers = GetLocalDNS()
|
||||
}
|
||||
if err = validateResolvers(c.Resolvers); err != nil {
|
||||
logging.Error.Fatalf("Resolvers validation failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = validateIPSources(c.IPSources); err != nil {
|
||||
logging.Error.Fatalf("IPSources validation failed: %v", err)
|
||||
}
|
||||
|
||||
c.Domain = strings.ToLower(c.Domain)
|
||||
|
||||
// SOA record fields
|
||||
c.SOARname = strings.TrimRight(strings.Replace(c.SOARname, "@", ".", -1), ".") + "."
|
||||
c.SOAMname = strings.TrimRight(c.SOAMname, ".") + "."
|
||||
c.SOASerial = uint32(time.Now().Unix())
|
||||
|
||||
// print configuration file
|
||||
logging.Verbose.Println("Mesos-DNS configuration:")
|
||||
logging.Verbose.Println(" - Masters: " + strings.Join(c.Masters, ", "))
|
||||
logging.Verbose.Println(" - Zookeeper: ", c.Zk)
|
||||
logging.Verbose.Println(" - ZookeeperDetectionTimeout: ", c.ZkDetectionTimeout)
|
||||
logging.Verbose.Println(" - RefreshSeconds: ", c.RefreshSeconds)
|
||||
logging.Verbose.Println(" - Domain: " + c.Domain)
|
||||
logging.Verbose.Println(" - Listener: " + c.Listener)
|
||||
logging.Verbose.Println(" - HTTPListener: " + c.HTTPListener)
|
||||
logging.Verbose.Println(" - Port: ", c.Port)
|
||||
logging.Verbose.Println(" - DnsOn: ", c.DNSOn)
|
||||
logging.Verbose.Println(" - TTL: ", c.TTL)
|
||||
logging.Verbose.Println(" - Timeout: ", c.Timeout)
|
||||
logging.Verbose.Println(" - StateTimeoutSeconds: ", c.StateTimeoutSeconds)
|
||||
logging.Verbose.Println(" - Resolvers: " + strings.Join(c.Resolvers, ", "))
|
||||
logging.Verbose.Println(" - ExternalOn: ", c.ExternalOn)
|
||||
logging.Verbose.Println(" - SOAMname: " + c.SOAMname)
|
||||
logging.Verbose.Println(" - SOARname: " + c.SOARname)
|
||||
logging.Verbose.Println(" - SOASerial: ", c.SOASerial)
|
||||
logging.Verbose.Println(" - SOARefresh: ", c.SOARefresh)
|
||||
logging.Verbose.Println(" - SOARetry: ", c.SOARetry)
|
||||
logging.Verbose.Println(" - SOAExpire: ", c.SOAExpire)
|
||||
logging.Verbose.Println(" - SOAExpire: ", c.SOAMinttl)
|
||||
logging.Verbose.Println(" - RecurseOn: ", c.RecurseOn)
|
||||
logging.Verbose.Println(" - HttpPort: ", c.HTTPPort)
|
||||
logging.Verbose.Println(" - HttpOn: ", c.HTTPOn)
|
||||
logging.Verbose.Println(" - ConfigFile: ", c.File)
|
||||
logging.Verbose.Println(" - EnforceRFC952: ", c.EnforceRFC952)
|
||||
logging.Verbose.Println(" - IPSources: ", c.IPSources)
|
||||
logging.Verbose.Println(" - EnumerationOn", c.EnumerationOn)
|
||||
|
||||
return *c
|
||||
}
|
||||
|
||||
func readConfig(file string) (*Config, error) {
|
||||
c := NewConfig()
|
||||
|
||||
workingDir := "."
|
||||
for _, name := range []string{"HOME", "USERPROFILE"} { // *nix, windows
|
||||
if dir := os.Getenv(name); dir != "" {
|
||||
workingDir = dir
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
c.File, err = filepath.Abs(strings.Replace(file, "~/", workingDir+"/", 1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot find configuration file")
|
||||
} else if bs, err := ioutil.ReadFile(c.File); err != nil {
|
||||
return nil, fmt.Errorf("missing configuration file: %q", c.File)
|
||||
} else if err = json.Unmarshal(bs, &c); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config file %q: %v", c.File, err)
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func unique(ss []string) []string {
|
||||
set := make(map[string]struct{}, len(ss))
|
||||
out := make([]string, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
if _, ok := set[s]; !ok {
|
||||
set[s] = struct{}{}
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GetLocalDNS returns the first nameserver in /etc/resolv.conf
|
||||
// Used for non-Mesos queries.
|
||||
func GetLocalDNS() []string {
|
||||
conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
logging.Error.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
return nonLocalAddies(conf.Servers)
|
||||
}
|
||||
|
||||
// Returns non-local nameserver entries
|
||||
func nonLocalAddies(cservers []string) []string {
|
||||
bad := localAddies()
|
||||
|
||||
good := []string{}
|
||||
|
||||
for i := 0; i < len(cservers); i++ {
|
||||
local := false
|
||||
for x := 0; x < len(bad); x++ {
|
||||
if cservers[i] == bad[x] {
|
||||
local = true
|
||||
}
|
||||
}
|
||||
|
||||
if !local {
|
||||
good = append(good, cservers[i])
|
||||
}
|
||||
}
|
||||
|
||||
return good
|
||||
}
|
||||
|
||||
// Returns an array of local ipv4 addresses
|
||||
func localAddies() []string {
|
||||
addies, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
|
||||
bad := []string{}
|
||||
|
||||
for i := 0; i < len(addies); i++ {
|
||||
ip, _, err := net.ParseCIDR(addies[i].String())
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
t4 := ip.To4()
|
||||
if t4 != nil {
|
||||
bad = append(bad, t4.String())
|
||||
}
|
||||
}
|
||||
|
||||
return bad
|
||||
}
|
655
integration/vendor/github.com/mesosphere/mesos-dns/records/generator.go
generated
vendored
Normal file
655
integration/vendor/github.com/mesosphere/mesos-dns/records/generator.go
generated
vendored
Normal file
|
@ -0,0 +1,655 @@
|
|||
// Package records contains functions to generate resource records from
|
||||
// mesos master states to serve through a dns server
|
||||
package records
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mesosphere/mesos-dns/errorutil"
|
||||
"github.com/mesosphere/mesos-dns/logging"
|
||||
"github.com/mesosphere/mesos-dns/models"
|
||||
"github.com/mesosphere/mesos-dns/records/labels"
|
||||
"github.com/mesosphere/mesos-dns/records/state"
|
||||
"github.com/tv42/zbase32"
|
||||
)
|
||||
|
||||
// Map host/service name to DNS answer
|
||||
// REFACTOR - when discoveryinfo is integrated
|
||||
// Will likely become map[string][]discoveryinfo
|
||||
// Effectively we're (ab)using the map type as a set
|
||||
// It used to have the type: rrs map[string][]string
|
||||
type rrs map[string]map[string]struct{}
|
||||
|
||||
func (r rrs) add(name, host string) bool {
|
||||
if host == "" {
|
||||
return false
|
||||
}
|
||||
v, ok := r[name]
|
||||
if !ok {
|
||||
v = make(map[string]struct{})
|
||||
r[name] = v
|
||||
} else {
|
||||
// don't overwrite existing values
|
||||
_, ok = v[host]
|
||||
if ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
v[host] = struct{}{}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r rrs) First(name string) (string, bool) {
|
||||
for host := range r[name] {
|
||||
return host, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Transform the record set into something exportable via the REST API
|
||||
func (r rrs) ToAXFRResourceRecordSet() models.AXFRResourceRecordSet {
|
||||
ret := make(models.AXFRResourceRecordSet, len(r))
|
||||
for host, values := range r {
|
||||
ret[host] = make([]string, 0, len(values))
|
||||
for record := range values {
|
||||
ret[host] = append(ret[host], record)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type rrsKind string
|
||||
|
||||
const (
|
||||
// A record types
|
||||
A rrsKind = "A"
|
||||
// SRV record types
|
||||
SRV = "SRV"
|
||||
)
|
||||
|
||||
func (kind rrsKind) rrs(rg *RecordGenerator) rrs {
|
||||
switch kind {
|
||||
case A:
|
||||
return rg.As
|
||||
case SRV:
|
||||
return rg.SRVs
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// RecordGenerator contains DNS records and methods to access and manipulate
|
||||
// them. TODO(kozyraki): Refactor when discovery id is available.
|
||||
type RecordGenerator struct {
|
||||
As rrs
|
||||
SRVs rrs
|
||||
SlaveIPs map[string]string
|
||||
EnumData EnumerationData
|
||||
httpClient http.Client
|
||||
}
|
||||
|
||||
// EnumerableRecord is the lowest level object, and should map 1:1 with DNS records
|
||||
type EnumerableRecord struct {
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Rtype string `json:"rtype"`
|
||||
}
|
||||
|
||||
// EnumerableTask consists of the records derived from a task
|
||||
type EnumerableTask struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Records []EnumerableRecord `json:"records"`
|
||||
}
|
||||
|
||||
// EnumerableFramework is consistent of enumerable tasks, and include the name of the framework
|
||||
type EnumerableFramework struct {
|
||||
Tasks []*EnumerableTask `json:"tasks"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// EnumerationData is the top level container pointing to the
|
||||
// enumerable frameworks containing enumerable tasks
|
||||
type EnumerationData struct {
|
||||
Frameworks []*EnumerableFramework `json:"frameworks"`
|
||||
}
|
||||
|
||||
// NewRecordGenerator returns a RecordGenerator that's been configured with a timeout.
|
||||
func NewRecordGenerator(httpTimeout time.Duration) *RecordGenerator {
|
||||
enumData := EnumerationData{
|
||||
Frameworks: []*EnumerableFramework{},
|
||||
}
|
||||
rg := &RecordGenerator{
|
||||
httpClient: http.Client{Timeout: httpTimeout},
|
||||
EnumData: enumData,
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
// ParseState retrieves and parses the Mesos master /state.json and converts it
|
||||
// into DNS records.
|
||||
func (rg *RecordGenerator) ParseState(c Config, masters ...string) error {
|
||||
// find master -- return if error
|
||||
sj, err := rg.FindMaster(masters...)
|
||||
if err != nil {
|
||||
logging.Error.Println("no master")
|
||||
return err
|
||||
}
|
||||
if sj.Leader == "" {
|
||||
logging.Error.Println("Unexpected error")
|
||||
err = errors.New("empty master")
|
||||
return err
|
||||
}
|
||||
|
||||
hostSpec := labels.RFC1123
|
||||
if c.EnforceRFC952 {
|
||||
hostSpec = labels.RFC952
|
||||
}
|
||||
|
||||
return rg.InsertState(sj, c.Domain, c.SOARname, c.Listener, masters, c.IPSources, hostSpec)
|
||||
}
|
||||
|
||||
// Tries each master and looks for the leader
|
||||
// if no leader responds it errors
|
||||
func (rg *RecordGenerator) FindMaster(masters ...string) (state.State, error) {
|
||||
var sj state.State
|
||||
var leader string
|
||||
|
||||
if len(masters) > 0 {
|
||||
leader, masters = masters[0], masters[1:]
|
||||
}
|
||||
|
||||
// Check if ZK leader is correct
|
||||
if leader != "" {
|
||||
logging.VeryVerbose.Println("Zookeeper says the leader is: ", leader)
|
||||
ip, port, err := getProto(leader)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
|
||||
if sj, err = rg.loadWrap(ip, port); err == nil && sj.Leader != "" {
|
||||
return sj, nil
|
||||
}
|
||||
logging.Verbose.Println("Warning: Zookeeper is wrong about leader")
|
||||
if len(masters) == 0 {
|
||||
return sj, errors.New("no master")
|
||||
}
|
||||
logging.Verbose.Println("Warning: falling back to Masters config field: ", masters)
|
||||
}
|
||||
|
||||
// try each listed mesos master before dying
|
||||
for i, master := range masters {
|
||||
ip, port, err := getProto(master)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
|
||||
if sj, err = rg.loadWrap(ip, port); err == nil && sj.Leader == "" {
|
||||
logging.VeryVerbose.Println("Warning: not a leader - trying next one")
|
||||
if len(masters)-1 == i {
|
||||
return sj, errors.New("no master")
|
||||
}
|
||||
} else {
|
||||
return sj, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return sj, errors.New("no master")
|
||||
}
|
||||
|
||||
// Loads state.json from mesos master
|
||||
func (rg *RecordGenerator) loadFromMaster(ip string, port string) (state.State, error) {
|
||||
// REFACTOR: state.json security
|
||||
|
||||
var sj state.State
|
||||
u := url.URL{
|
||||
Scheme: "http",
|
||||
Host: net.JoinHostPort(ip, port),
|
||||
Path: "/master/state.json",
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
return state.State{}, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := rg.httpClient.Do(req)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
return state.State{}, err
|
||||
}
|
||||
|
||||
defer errorutil.Ignore(resp.Body.Close)
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
return state.State{}, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &sj)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
return state.State{}, err
|
||||
}
|
||||
|
||||
return sj, nil
|
||||
}
|
||||
|
||||
// Catches an attempt to load state.json from a mesos master
|
||||
// attempts can fail from down server or mesos master secondary
|
||||
// it also reloads from a different master if the master it attempted to
|
||||
// load from was not the leader
|
||||
func (rg *RecordGenerator) loadWrap(ip string, port string) (state.State, error) {
|
||||
var err error
|
||||
var sj state.State
|
||||
|
||||
logging.VeryVerbose.Println("reloading from master " + ip)
|
||||
sj, err = rg.loadFromMaster(ip, port)
|
||||
if err != nil {
|
||||
return state.State{}, err
|
||||
}
|
||||
if rip := leaderIP(sj.Leader); rip != ip {
|
||||
logging.VeryVerbose.Println("Warning: master changed to " + ip)
|
||||
sj, err = rg.loadFromMaster(rip, port)
|
||||
return sj, err
|
||||
}
|
||||
return sj, nil
|
||||
}
|
||||
|
||||
// hashes a given name using a truncated sha1 hash
|
||||
// 5 characters extracted from the zbase32 encoded hash provides
|
||||
// enough entropy to avoid collisions
|
||||
// zbase32: http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
|
||||
// is used to promote human-readable names
|
||||
func hashString(s string) string {
|
||||
hash := sha1.Sum([]byte(s))
|
||||
return zbase32.EncodeToString(hash[:])[:5]
|
||||
}
|
||||
|
||||
// attempt to translate the hostname into an IPv4 address. logs an error if IP
|
||||
// lookup fails. if an IP address cannot be found, returns the same hostname
|
||||
// that was given. upon success returns the IP address as a string.
|
||||
func hostToIP4(hostname string) (string, bool) {
|
||||
ip := net.ParseIP(hostname)
|
||||
if ip == nil {
|
||||
t, err := net.ResolveIPAddr("ip4", hostname)
|
||||
if err != nil {
|
||||
logging.Error.Printf("cannot translate hostname %q into an ip4 address", hostname)
|
||||
return hostname, false
|
||||
}
|
||||
ip = t.IP
|
||||
}
|
||||
return ip.String(), true
|
||||
}
|
||||
|
||||
// InsertState transforms a StateJSON into RecordGenerator RRs
|
||||
func (rg *RecordGenerator) InsertState(sj state.State, domain, ns, listener string, masters, ipSources []string, spec labels.Func) error {
|
||||
|
||||
rg.SlaveIPs = map[string]string{}
|
||||
rg.SRVs = rrs{}
|
||||
rg.As = rrs{}
|
||||
rg.frameworkRecords(sj, domain, spec)
|
||||
rg.slaveRecords(sj, domain, spec)
|
||||
rg.listenerRecord(listener, ns)
|
||||
rg.masterRecord(domain, masters, sj.Leader)
|
||||
rg.taskRecords(sj, domain, spec, ipSources)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// frameworkRecords injects A and SRV records into the generator store:
|
||||
// frameworkname.domain. // resolves to IPs of each framework
|
||||
// _framework._tcp.frameworkname.domain. // resolves to the driver port and IP of each framework
|
||||
func (rg *RecordGenerator) frameworkRecords(sj state.State, domain string, spec labels.Func) {
|
||||
for _, f := range sj.Frameworks {
|
||||
fname := labels.DomainFrag(f.Name, labels.Sep, spec)
|
||||
host, port := f.HostPort()
|
||||
if address, ok := hostToIP4(host); ok {
|
||||
a := fname + "." + domain + "."
|
||||
rg.insertRR(a, address, A)
|
||||
if port != "" {
|
||||
srvAddress := net.JoinHostPort(a, port)
|
||||
rg.insertRR("_framework._tcp."+a, srvAddress, SRV)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// slaveRecords injects A and SRV records into the generator store:
|
||||
// slave.domain. // resolves to IPs of all slaves
|
||||
// _slave._tc.domain. // resolves to the driver port and IP of all slaves
|
||||
func (rg *RecordGenerator) slaveRecords(sj state.State, domain string, spec labels.Func) {
|
||||
for _, slave := range sj.Slaves {
|
||||
address, ok := hostToIP4(slave.PID.Host)
|
||||
if ok {
|
||||
a := "slave." + domain + "."
|
||||
rg.insertRR(a, address, A)
|
||||
srv := net.JoinHostPort(a, slave.PID.Port)
|
||||
rg.insertRR("_slave._tcp."+domain+".", srv, SRV)
|
||||
} else {
|
||||
logging.VeryVerbose.Printf("string '%q' for slave with id %q is not a valid IP address", address, slave.ID)
|
||||
address = labels.DomainFrag(address, labels.Sep, spec)
|
||||
}
|
||||
rg.SlaveIPs[slave.ID] = address
|
||||
}
|
||||
}
|
||||
|
||||
// masterRecord injects A and SRV records into the generator store:
|
||||
// master.domain. // resolves to IPs of all masters
|
||||
// masterN.domain. // one IP address for each master
|
||||
// leader.domain. // one IP address for the leading master
|
||||
//
|
||||
// The current func implementation makes an assumption about the order of masters:
|
||||
// it's the order in which you expect the enumerated masterN records to be created.
|
||||
// This is probably important: if a new leader is elected, you may not want it to
|
||||
// become master0 simply because it's the leader. You probably want your DNS records
|
||||
// to change as little as possible. And this func should have the least impact on
|
||||
// enumeration order, or name/IP mappings - it's just creating the records. So let
|
||||
// the caller do the work of ordering/sorting (if desired) the masters list if a
|
||||
// different outcome is desired.
|
||||
//
|
||||
// Another consequence of the current overall mesos-dns app implementation is that
|
||||
// the leader may not even be in the masters list at some point in time. masters is
|
||||
// really fallback-masters (only consider these to be masters if I can't find a
|
||||
// leader via ZK). At some point in time, they may not actually be masters any more.
|
||||
// Consider a cluster of 3 nodes that suffers the loss of a member, and gains a new
|
||||
// member (VM crashed, was replaced by another VM). And the cycle repeats several
|
||||
// times. You end up with a set of running masters (and leader) that's different
|
||||
// than the set of statically configured fallback masters.
|
||||
//
|
||||
// So the func tries to index the masters as they're listed and begrudgingly assigns
|
||||
// the leading master an index out-of-band if it's not actually listed in the masters
|
||||
// list. There are probably better ways to do it.
|
||||
func (rg *RecordGenerator) masterRecord(domain string, masters []string, leader string) {
|
||||
// create records for leader
|
||||
// A records
|
||||
h := strings.Split(leader, "@")
|
||||
if len(h) < 2 {
|
||||
logging.Error.Println(leader)
|
||||
return // avoid a panic later
|
||||
}
|
||||
leaderAddress := h[1]
|
||||
ip, port, err := getProto(leaderAddress)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
return
|
||||
}
|
||||
arec := "leader." + domain + "."
|
||||
rg.insertRR(arec, ip, A)
|
||||
arec = "master." + domain + "."
|
||||
rg.insertRR(arec, ip, A)
|
||||
|
||||
// SRV records
|
||||
tcp := "_leader._tcp." + domain + "."
|
||||
udp := "_leader._udp." + domain + "."
|
||||
host := "leader." + domain + "." + ":" + port
|
||||
rg.insertRR(tcp, host, SRV)
|
||||
rg.insertRR(udp, host, SRV)
|
||||
|
||||
// if there is a list of masters, insert that as well
|
||||
addedLeaderMasterN := false
|
||||
idx := 0
|
||||
for _, master := range masters {
|
||||
masterIP, _, err := getProto(master)
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// A records (master and masterN)
|
||||
if master != leaderAddress {
|
||||
arec := "master." + domain + "."
|
||||
added := rg.insertRR(arec, masterIP, A)
|
||||
if !added {
|
||||
// duplicate master?!
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if master == leaderAddress && addedLeaderMasterN {
|
||||
// duplicate leader in masters list?!
|
||||
continue
|
||||
}
|
||||
|
||||
arec := "master" + strconv.Itoa(idx) + "." + domain + "."
|
||||
rg.insertRR(arec, masterIP, A)
|
||||
idx++
|
||||
|
||||
if master == leaderAddress {
|
||||
addedLeaderMasterN = true
|
||||
}
|
||||
}
|
||||
// flake: we ended up with a leader that's not in the list of all masters?
|
||||
if !addedLeaderMasterN {
|
||||
// only a flake if there were fallback masters configured
|
||||
if len(masters) > 0 {
|
||||
logging.Error.Printf("warning: leader %q is not in master list", leader)
|
||||
}
|
||||
arec = "master" + strconv.Itoa(idx) + "." + domain + "."
|
||||
rg.insertRR(arec, ip, A)
|
||||
}
|
||||
}
|
||||
|
||||
// A record for mesos-dns (the name is listed in SOA replies)
|
||||
func (rg *RecordGenerator) listenerRecord(listener string, ns string) {
|
||||
if listener == "0.0.0.0" {
|
||||
rg.setFromLocal(listener, ns)
|
||||
} else if listener == "127.0.0.1" {
|
||||
rg.insertRR(ns, "127.0.0.1", A)
|
||||
} else {
|
||||
rg.insertRR(ns, listener, A)
|
||||
}
|
||||
}
|
||||
|
||||
func (rg *RecordGenerator) taskRecords(sj state.State, domain string, spec labels.Func, ipSources []string) {
|
||||
for _, f := range sj.Frameworks {
|
||||
enumerableFramework := &EnumerableFramework{
|
||||
Name: f.Name,
|
||||
Tasks: []*EnumerableTask{},
|
||||
}
|
||||
rg.EnumData.Frameworks = append(rg.EnumData.Frameworks, enumerableFramework)
|
||||
|
||||
for _, task := range f.Tasks {
|
||||
var ok bool
|
||||
task.SlaveIP, ok = rg.SlaveIPs[task.SlaveID]
|
||||
|
||||
// only do running and discoverable tasks
|
||||
if ok && (task.State == "TASK_RUNNING") {
|
||||
rg.taskRecord(task, f, domain, spec, ipSources, enumerableFramework)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type context struct {
|
||||
taskName,
|
||||
taskID,
|
||||
slaveID,
|
||||
taskIP,
|
||||
slaveIP string
|
||||
}
|
||||
|
||||
func (rg *RecordGenerator) taskRecord(task state.Task, f state.Framework, domain string, spec labels.Func, ipSources []string, enumFW *EnumerableFramework) {
|
||||
|
||||
newTask := &EnumerableTask{ID: task.ID, Name: task.Name}
|
||||
|
||||
enumFW.Tasks = append(enumFW.Tasks, newTask)
|
||||
|
||||
// define context
|
||||
ctx := context{
|
||||
spec(task.Name),
|
||||
hashString(task.ID),
|
||||
slaveIDTail(task.SlaveID),
|
||||
task.IP(ipSources...),
|
||||
task.SlaveIP,
|
||||
}
|
||||
|
||||
// use DiscoveryInfo name if defined instead of task name
|
||||
if task.HasDiscoveryInfo() {
|
||||
// LEGACY TODO: REMOVE
|
||||
ctx.taskName = task.DiscoveryInfo.Name
|
||||
rg.taskContextRecord(ctx, task, f, domain, spec, newTask)
|
||||
// LEGACY, TODO: REMOVE
|
||||
|
||||
ctx.taskName = spec(task.DiscoveryInfo.Name)
|
||||
rg.taskContextRecord(ctx, task, f, domain, spec, newTask)
|
||||
} else {
|
||||
rg.taskContextRecord(ctx, task, f, domain, spec, newTask)
|
||||
}
|
||||
|
||||
}
|
||||
func (rg *RecordGenerator) taskContextRecord(ctx context, task state.Task, f state.Framework, domain string, spec labels.Func, enumTask *EnumerableTask) {
|
||||
fname := labels.DomainFrag(f.Name, labels.Sep, spec)
|
||||
|
||||
tail := "." + domain + "."
|
||||
|
||||
// insert canonical A records
|
||||
canonical := ctx.taskName + "-" + ctx.taskID + "-" + ctx.slaveID + "." + fname
|
||||
arec := ctx.taskName + "." + fname
|
||||
|
||||
rg.insertTaskRR(arec+tail, ctx.taskIP, A, enumTask)
|
||||
rg.insertTaskRR(canonical+tail, ctx.taskIP, A, enumTask)
|
||||
|
||||
rg.insertTaskRR(arec+".slave"+tail, ctx.slaveIP, A, enumTask)
|
||||
rg.insertTaskRR(canonical+".slave"+tail, ctx.slaveIP, A, enumTask)
|
||||
|
||||
// recordName generates records for ctx.taskName, given some generation chain
|
||||
recordName := func(gen chain) { gen("_" + ctx.taskName) }
|
||||
|
||||
// asSRV is always the last link in a chain, it must insert RR's
|
||||
asSRV := func(target string) chain {
|
||||
return func(records ...string) {
|
||||
for i := range records {
|
||||
name := records[i] + tail
|
||||
rg.insertTaskRR(name, target, SRV, enumTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add RFC 2782 SRV records
|
||||
var subdomains []string
|
||||
if task.HasDiscoveryInfo() {
|
||||
subdomains = []string{"slave"}
|
||||
} else {
|
||||
subdomains = []string{"slave", domainNone}
|
||||
}
|
||||
|
||||
slaveHost := canonical + ".slave" + tail
|
||||
for _, port := range task.Ports() {
|
||||
slaveTarget := slaveHost + ":" + port
|
||||
recordName(withProtocol(protocolNone, fname, spec,
|
||||
withSubdomains(subdomains, asSRV(slaveTarget))))
|
||||
}
|
||||
|
||||
if !task.HasDiscoveryInfo() {
|
||||
return
|
||||
}
|
||||
|
||||
for _, port := range task.DiscoveryInfo.Ports.DiscoveryPorts {
|
||||
target := canonical + tail + ":" + strconv.Itoa(port.Number)
|
||||
recordName(withProtocol(port.Protocol, fname, spec,
|
||||
withNamedPort(port.Name, spec, asSRV(target))))
|
||||
}
|
||||
}
|
||||
|
||||
// A records for each local interface
|
||||
// If this causes problems you should explicitly set the
|
||||
// listener address in config.json
|
||||
func (rg *RecordGenerator) setFromLocal(host string, ns string) {
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
|
||||
// handle err
|
||||
for _, i := range ifaces {
|
||||
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
logging.Error.Println(err)
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rg.insertRR(ns, ip.String(), A)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insertRR adds a record to the appropriate record map for the given name/host pair,
|
||||
// but only if the pair is unique. returns true if added, false otherwise.
|
||||
// TODO(???): REFACTOR when storage is updated
|
||||
func (rg *RecordGenerator) insertTaskRR(name, host string, kind rrsKind, enumTask *EnumerableTask) bool {
|
||||
if rg.insertRR(name, host, kind) {
|
||||
enumRecord := EnumerableRecord{Name: name, Host: host, Rtype: string(kind)}
|
||||
enumTask.Records = append(enumTask.Records, enumRecord)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (rg *RecordGenerator) insertRR(name, host string, kind rrsKind) (added bool) {
|
||||
if rrs := kind.rrs(rg); rrs != nil {
|
||||
if added = rrs.add(name, host); added {
|
||||
logging.VeryVerbose.Println("[" + string(kind) + "]\t" + name + ": " + host)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// leaderIP returns the ip for the mesos master
|
||||
// input format master@ip:port
|
||||
func leaderIP(leader string) string {
|
||||
pair := strings.Split(leader, "@")[1]
|
||||
return strings.Split(pair, ":")[0]
|
||||
}
|
||||
|
||||
// return the slave number from a Mesos slave id
|
||||
func slaveIDTail(slaveID string) string {
|
||||
fields := strings.Split(slaveID, "-")
|
||||
return strings.ToLower(fields[len(fields)-1])
|
||||
}
|
||||
|
||||
// should be able to accept
|
||||
// ip:port
|
||||
// zk://host1:port1,host2:port2,.../path
|
||||
// zk://username:password@host1:port1,host2:port2,.../path
|
||||
// file:///path/to/file (where file contains one of the above)
|
||||
func getProto(pair string) (string, string, error) {
|
||||
h := strings.SplitN(pair, ":", 2)
|
||||
if len(h) != 2 {
|
||||
return "", "", fmt.Errorf("unable to parse proto from %q", pair)
|
||||
}
|
||||
return h[0], h[1], nil
|
||||
}
|
83
integration/vendor/github.com/mesosphere/mesos-dns/records/labels/labels.go
generated
vendored
Normal file
83
integration/vendor/github.com/mesosphere/mesos-dns/records/labels/labels.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Sep is the default domain fragment separator.
|
||||
const Sep = "."
|
||||
|
||||
// DomainFrag mangles the given name in order to produce a valid domain fragment.
|
||||
// A valid domain fragment will consist of one or more host name labels
|
||||
// concatenated by the given separator.
|
||||
func DomainFrag(name, sep string, label Func) string {
|
||||
var labels []string
|
||||
for _, part := range strings.Split(name, sep) {
|
||||
if lab := label(part); lab != "" {
|
||||
labels = append(labels, lab)
|
||||
}
|
||||
}
|
||||
return strings.Join(labels, sep)
|
||||
}
|
||||
|
||||
// Func is a function type representing label functions.
|
||||
type Func func(string) string
|
||||
|
||||
// RFC952 mangles a name to conform to the DNS label rules specified in RFC952.
|
||||
// See http://www.rfc-base.org/txt/rfc-952.txt
|
||||
func RFC952(name string) string {
|
||||
return string(label([]byte(name), 24, "-0123456789", "-"))
|
||||
}
|
||||
|
||||
// RFC1123 mangles a name to conform to the DNS label rules specified in RFC1123.
|
||||
// See http://www.rfc-base.org/txt/rfc-1123.txt
|
||||
func RFC1123(name string) string {
|
||||
return string(label([]byte(name), 63, "-", "-"))
|
||||
}
|
||||
|
||||
// label computes a label from the given name with maxlen length and the
|
||||
// left and right cutsets trimmed from their respective ends.
|
||||
func label(name []byte, maxlen int, left, right string) []byte {
|
||||
return trimCut(bytes.Map(mapping, name), maxlen, left, right)
|
||||
}
|
||||
|
||||
// mapping maps a given rune to its valid DNS label counterpart.
|
||||
func mapping(r rune) rune {
|
||||
switch {
|
||||
case r >= 'A' && r <= 'Z':
|
||||
return r - ('A' - 'a')
|
||||
case r >= 'a' && r <= 'z':
|
||||
fallthrough
|
||||
case r >= '0' && r <= '9':
|
||||
return r
|
||||
case r == '-' || r == '.' || r == '_':
|
||||
return '-'
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
// trimCut cuts the given label at min(maxlen, len(label)) and ensures the left
|
||||
// and right cutsets are trimmed from their respective ends.
|
||||
func trimCut(label []byte, maxlen int, left, right string) []byte {
|
||||
trim := bytes.TrimLeft(label, left)
|
||||
size := min(len(trim), maxlen)
|
||||
head := bytes.TrimRight(trim[:size], right)
|
||||
if len(head) == size {
|
||||
return head
|
||||
}
|
||||
tail := bytes.TrimLeft(trim[size:], right)
|
||||
if len(tail) > 0 {
|
||||
return append(head, tail[:size-len(head)]...)
|
||||
}
|
||||
return head
|
||||
}
|
||||
|
||||
// min returns the minimum of two ints
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
271
integration/vendor/github.com/mesosphere/mesos-dns/records/state/state.go
generated
vendored
Normal file
271
integration/vendor/github.com/mesosphere/mesos-dns/records/state/state.go
generated
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Resources holds resources as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Resources struct {
|
||||
PortRanges string `json:"ports"`
|
||||
}
|
||||
|
||||
// Ports returns a slice of individual ports expanded from PortRanges.
|
||||
func (r Resources) Ports() []string {
|
||||
if r.PortRanges == "" || r.PortRanges == "[]" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
rhs := strings.Split(r.PortRanges, "[")[1]
|
||||
lhs := strings.Split(rhs, "]")[0]
|
||||
|
||||
yports := []string{}
|
||||
|
||||
mports := strings.Split(lhs, ",")
|
||||
for _, port := range mports {
|
||||
tmp := strings.TrimSpace(port)
|
||||
pz := strings.Split(tmp, "-")
|
||||
lo, _ := strconv.Atoi(pz[0])
|
||||
hi, _ := strconv.Atoi(pz[1])
|
||||
|
||||
for t := lo; t <= hi; t++ {
|
||||
yports = append(yports, strconv.Itoa(t))
|
||||
}
|
||||
}
|
||||
return yports
|
||||
}
|
||||
|
||||
// Label holds a label as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Label struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Status holds a task status as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Status struct {
|
||||
Timestamp float64 `json:"timestamp"`
|
||||
State string `json:"state"`
|
||||
Labels []Label `json:"labels,omitempty"`
|
||||
ContainerStatus ContainerStatus `json:"container_status,omitempty"`
|
||||
Healthy *bool `json:"healthy"`
|
||||
}
|
||||
|
||||
// ContainerStatus holds container metadata as defined in the /state.json
|
||||
// Mesos HTTP endpoint.
|
||||
type ContainerStatus struct {
|
||||
NetworkInfos []NetworkInfo `json:"network_infos,omitempty"`
|
||||
}
|
||||
|
||||
// NetworkInfo holds the network configuration for a single interface
|
||||
// as defined in the /state.json Mesos HTTP endpoint.
|
||||
type NetworkInfo struct {
|
||||
IPAddresses []IPAddress `json:"ip_addresses,omitempty"`
|
||||
// back-compat with 0.25 IPAddress format
|
||||
IPAddress string `json:"ip_address,omitempty"`
|
||||
}
|
||||
|
||||
// IPAddress holds a single IP address configured on an interface,
|
||||
// as defined in the /state.json Mesos HTTP endpoint.
|
||||
type IPAddress struct {
|
||||
IPAddress string `json:"ip_address,omitempty"`
|
||||
}
|
||||
|
||||
// Task holds a task as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Task struct {
|
||||
FrameworkID string `json:"framework_id"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SlaveID string `json:"slave_id"`
|
||||
State string `json:"state"`
|
||||
Statuses []Status `json:"statuses"`
|
||||
Resources `json:"resources"`
|
||||
DiscoveryInfo DiscoveryInfo `json:"discovery"`
|
||||
|
||||
SlaveIP string `json:"-"`
|
||||
Labels []Label `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// HasDiscoveryInfo return whether the DiscoveryInfo was provided in the state.json
|
||||
func (t *Task) HasDiscoveryInfo() bool {
|
||||
return t.DiscoveryInfo.Name != ""
|
||||
}
|
||||
|
||||
// IP returns the first Task IP found in the given sources.
|
||||
func (t *Task) IP(srcs ...string) string {
|
||||
if ips := t.IPs(srcs...); len(ips) > 0 {
|
||||
return ips[0].String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IPs returns a slice of IPs sourced from the given sources with ascending
|
||||
// priority.
|
||||
func (t *Task) IPs(srcs ...string) (ips []net.IP) {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
for i := range srcs {
|
||||
if src, ok := sources[srcs[i]]; ok {
|
||||
for _, srcIP := range src(t) {
|
||||
if ip := net.ParseIP(srcIP); len(ip) > 0 {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
// sources maps the string representation of IP sources to their functions.
|
||||
var sources = map[string]func(*Task) []string{
|
||||
"host": hostIPs,
|
||||
"mesos": mesosIPs,
|
||||
"docker": dockerIPs,
|
||||
"netinfo": networkInfoIPs,
|
||||
}
|
||||
|
||||
// hostIPs is an IPSource which returns the IP addresses of the slave a Task
|
||||
// runs on.
|
||||
func hostIPs(t *Task) []string { return []string{t.SlaveIP} }
|
||||
|
||||
// networkInfoIPs returns IP addresses from a given Task's
|
||||
// []Status.ContainerStatus.[]NetworkInfos.[]IPAddresses.IPAddress
|
||||
func networkInfoIPs(t *Task) []string {
|
||||
return statusIPs(t.Statuses, func(s *Status) []string {
|
||||
ips := make([]string, len(s.ContainerStatus.NetworkInfos))
|
||||
for _, netinfo := range s.ContainerStatus.NetworkInfos {
|
||||
if len(netinfo.IPAddresses) > 0 {
|
||||
// In v0.26, we use the IPAddresses field.
|
||||
for _, ipAddress := range netinfo.IPAddresses {
|
||||
ips = append(ips, ipAddress.IPAddress)
|
||||
}
|
||||
} else {
|
||||
// Fall back to v0.25 syntax of single IPAddress if that's being used.
|
||||
if netinfo.IPAddress != "" {
|
||||
ips = append(ips, netinfo.IPAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ips
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
// DockerIPLabel is the key of the Label which holds the Docker containerizer IP value.
|
||||
DockerIPLabel = "Docker.NetworkSettings.IPAddress"
|
||||
// MesosIPLabel is the key of the label which holds the Mesos containerizer IP value.
|
||||
MesosIPLabel = "MesosContainerizer.NetworkSettings.IPAddress"
|
||||
)
|
||||
|
||||
// dockerIPs returns IP addresses from the values of all
|
||||
// Task.[]Status.[]Labels whose keys are equal to "Docker.NetworkSettings.IPAddress".
|
||||
func dockerIPs(t *Task) []string {
|
||||
return statusIPs(t.Statuses, labels(DockerIPLabel))
|
||||
}
|
||||
|
||||
// mesosIPs returns IP addresses from the values of all
|
||||
// Task.[]Status.[]Labels whose keys are equal to
|
||||
// "MesosContainerizer.NetworkSettings.IPAddress".
|
||||
func mesosIPs(t *Task) []string {
|
||||
return statusIPs(t.Statuses, labels(MesosIPLabel))
|
||||
}
|
||||
|
||||
// statusIPs returns the latest running status IPs extracted with the given src
|
||||
func statusIPs(st []Status, src func(*Status) []string) []string {
|
||||
// the state.json we extract from mesos makes no guarantees re: the order
|
||||
// of the task statuses so we should check the timestamps to avoid problems
|
||||
// down the line. we can't rely on seeing the same sequence. (@joris)
|
||||
// https://github.com/apache/mesos/blob/0.24.0/src/slave/slave.cpp#L5226-L5238
|
||||
ts, j := -1.0, -1
|
||||
for i := range st {
|
||||
if st[i].State == "TASK_RUNNING" && st[i].Timestamp > ts {
|
||||
ts, j = st[i].Timestamp, i
|
||||
}
|
||||
}
|
||||
if j >= 0 {
|
||||
return src(&st[j])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// labels returns all given Status.[]Labels' values whose keys are equal
|
||||
// to the given key
|
||||
func labels(key string) func(*Status) []string {
|
||||
return func(s *Status) []string {
|
||||
vs := make([]string, 0, len(s.Labels))
|
||||
for _, l := range s.Labels {
|
||||
if l.Key == key {
|
||||
vs = append(vs, l.Value)
|
||||
}
|
||||
}
|
||||
return vs
|
||||
}
|
||||
}
|
||||
|
||||
// Framework holds a framework as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Framework struct {
|
||||
Tasks []Task `json:"tasks"`
|
||||
PID PID `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
// HostPort returns the hostname and port where a framework's scheduler is
|
||||
// listening on.
|
||||
func (f Framework) HostPort() (string, string) {
|
||||
if f.PID.UPID != nil {
|
||||
return f.PID.Host, f.PID.Port
|
||||
}
|
||||
return f.Hostname, ""
|
||||
}
|
||||
|
||||
// Slave holds a slave as defined in the /state.json Mesos HTTP endpoint.
|
||||
type Slave struct {
|
||||
ID string `json:"id"`
|
||||
Hostname string `json:"hostname"`
|
||||
PID PID `json:"pid"`
|
||||
}
|
||||
|
||||
// PID holds a Mesos PID and implements the json.Unmarshaler interface.
|
||||
type PID struct{ *upid.UPID }
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface for PIDs.
|
||||
func (p *PID) UnmarshalJSON(data []byte) (err error) {
|
||||
p.UPID, err = upid.Parse(string(bytes.Trim(data, `" `)))
|
||||
return err
|
||||
}
|
||||
|
||||
// State holds the state defined in the /state.json Mesos HTTP endpoint.
|
||||
type State struct {
|
||||
Frameworks []Framework `json:"frameworks"`
|
||||
Slaves []Slave `json:"slaves"`
|
||||
Leader string `json:"leader"`
|
||||
}
|
||||
|
||||
// DiscoveryInfo holds the discovery meta data for a task defined in the /state.json Mesos HTTP endpoint.
|
||||
type DiscoveryInfo struct {
|
||||
Visibilty string `json:"visibility"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Location string `json:"location,omitempty"`
|
||||
Environment string `json:"environment,omitempty"`
|
||||
Labels struct {
|
||||
Labels []Label `json:"labels"`
|
||||
} `json:"labels"`
|
||||
Ports Ports `json:"ports"`
|
||||
}
|
||||
|
||||
// Ports holds a list of DiscoveryPort
|
||||
type Ports struct {
|
||||
DiscoveryPorts []DiscoveryPort `json:"ports"`
|
||||
}
|
||||
|
||||
// DiscoveryPort holds a port for a task defined in the /state.json Mesos HTTP endpoint.
|
||||
type DiscoveryPort struct {
|
||||
Protocol string `json:"protocol"`
|
||||
Number int `json:"number"`
|
||||
Name string `json:"name"`
|
||||
}
|
84
integration/vendor/github.com/mesosphere/mesos-dns/records/validation.go
generated
vendored
Normal file
84
integration/vendor/github.com/mesosphere/mesos-dns/records/validation.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func validateEnabledServices(c *Config) error {
|
||||
if !c.DNSOn && !c.HTTPOn {
|
||||
return fmt.Errorf("Either DNS or HTTP server should be on")
|
||||
}
|
||||
if len(c.Masters) == 0 && c.Zk == "" {
|
||||
return fmt.Errorf("specify mesos masters or zookeeper in config.json")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateMasters checks that each master in the list is a properly formatted host:ip pair.
|
||||
// duplicate masters in the list are not allowed.
|
||||
// returns nil if the masters list is empty, or else all masters in the list are valid.
|
||||
func validateMasters(ms []string) error {
|
||||
if len(ms) == 0 {
|
||||
return nil
|
||||
}
|
||||
valid := make(map[string]struct{}, len(ms))
|
||||
for i, m := range ms {
|
||||
h, p, err := net.SplitHostPort(m)
|
||||
if err != nil {
|
||||
return fmt.Errorf("illegal host:port specified for master %q", ms[i])
|
||||
}
|
||||
// normalize ipv6 addresses
|
||||
if ip := net.ParseIP(h); ip != nil {
|
||||
h = ip.String()
|
||||
m = h + "_" + p
|
||||
}
|
||||
//TODO(jdef) distinguish between intended hostnames and invalid ip addresses
|
||||
if _, found := valid[m]; found {
|
||||
return fmt.Errorf("duplicate master specified: %v", ms[i])
|
||||
}
|
||||
valid[m] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateResolvers checks that each resolver in the list is a properly formatted IP address.
|
||||
// duplicate resolvers in the list are not allowed.
|
||||
// returns nil if the resolver list is empty, or else all resolvers in the list are valid.
|
||||
func validateResolvers(rs []string) error {
|
||||
if len(rs) == 0 {
|
||||
return nil
|
||||
}
|
||||
ips := make(map[string]struct{}, len(rs))
|
||||
for _, r := range rs {
|
||||
ip := net.ParseIP(r)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("illegal IP specified for resolver %q", r)
|
||||
}
|
||||
ipstr := ip.String()
|
||||
if _, found := ips[ipstr]; found {
|
||||
return fmt.Errorf("duplicate resolver IP specified: %v", r)
|
||||
}
|
||||
ips[ipstr] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateIPSources checks validity of ip sources
|
||||
func validateIPSources(srcs []string) error {
|
||||
if len(srcs) == 0 {
|
||||
return fmt.Errorf("empty ip sources")
|
||||
}
|
||||
if len(srcs) != len(unique(srcs)) {
|
||||
return fmt.Errorf("duplicate ip source specified")
|
||||
}
|
||||
for _, src := range srcs {
|
||||
switch src {
|
||||
case "host", "docker", "mesos", "netinfo":
|
||||
default:
|
||||
return fmt.Errorf("invalid ip source %q", src)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
54
integration/vendor/github.com/mesosphere/mesos-dns/util/util.go
generated
vendored
Normal file
54
integration/vendor/github.com/mesosphere/mesos-dns/util/util.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright 2014 Google Inc. 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// ReallyCrash is for testing, to bypass HandleCrash.
|
||||
var ReallyCrash bool
|
||||
|
||||
// PanicHandlers is a list of functions which will be invoked when a panic happens.
|
||||
var PanicHandlers = []func(interface{}){logPanic}
|
||||
|
||||
// HandleCrash simply catches a crash and logs an error. Meant to be called via defer.
|
||||
func HandleCrash() {
|
||||
if ReallyCrash {
|
||||
return
|
||||
}
|
||||
if r := recover(); r != nil {
|
||||
for _, fn := range PanicHandlers {
|
||||
fn(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// logPanic logs the caller tree when a panic occurs.
|
||||
func logPanic(r interface{}) {
|
||||
callers := ""
|
||||
for i := 0; true; i++ {
|
||||
_, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
callers = callers + fmt.Sprintf("%v:%v\n", file, line)
|
||||
}
|
||||
log.Printf("Recovered from panic: %#v (%v)\n%v", r, r, callers)
|
||||
}
|
4
integration/vendor/github.com/mesosphere/mesos-dns/version.go
generated
vendored
Normal file
4
integration/vendor/github.com/mesosphere/mesos-dns/version.go
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
|
||||
// Version is the Mesos-DNS version string, set at build time.
|
||||
var Version = "dev"
|
Loading…
Add table
Add a link
Reference in a new issue