Skip to content

Commit

Permalink
Add basic enumeration of records to mesos-dns
Browse files Browse the repository at this point in the history
  • Loading branch information
sargun committed Mar 1, 2016
1 parent 67fcbbd commit 6f90aee
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 18 deletions.
3 changes: 2 additions & 1 deletion config.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
"externalon": true,
"recurseon": true,
"IPSources": ["mesos", "host"],
"EnforceRFC952": false
"EnforceRFC952": false,
"EnumerationOn": true
}
4 changes: 4 additions & 0 deletions records/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ type Config struct {
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
Expand All @@ -90,6 +92,7 @@ func NewConfig() Config {
ExternalOn: true,
RecurseOn: true,
IPSources: []string{"netinfo", "mesos", "host"},
EnumerationOn: true,
}
}

Expand Down Expand Up @@ -157,6 +160,7 @@ func SetConfig(cjson string) Config {
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
}
Expand Down
72 changes: 55 additions & 17 deletions records/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,36 @@ 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 {
rg := &RecordGenerator{httpClient: http.Client{Timeout: httpTimeout}}
Expand Down Expand Up @@ -363,14 +390,16 @@ func (rg *RecordGenerator) listenerRecord(listener string, ns string) {

func (rg *RecordGenerator) taskRecords(sj state.State, domain string, spec labels.Func, ipSources []string) {
for _, f := range sj.Frameworks {
enumerableFramework := &EnumerableFramework{Name: f.Name}
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)
rg.taskRecord(task, f, domain, spec, ipSources, enumerableFramework)
}
}
}
Expand All @@ -384,7 +413,11 @@ type context struct {
slaveIP string
}

func (rg *RecordGenerator) taskRecord(task state.Task, f state.Framework, domain string, spec labels.Func, ipSources []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{
Expand All @@ -399,17 +432,17 @@ func (rg *RecordGenerator) taskRecord(task state.Task, f state.Framework, domain
if task.HasDiscoveryInfo() {
// LEGACY TODO: REMOVE
ctx.taskName = task.DiscoveryInfo.Name
rg.taskContextRecord(ctx, task, f, domain, spec)
rg.taskContextRecord(ctx, task, f, domain, spec, newTask)
// LEGACY, TODO: REMOVE

ctx.taskName = spec(task.DiscoveryInfo.Name)
rg.taskContextRecord(ctx, task, f, domain, spec)
rg.taskContextRecord(ctx, task, f, domain, spec, newTask)
} else {
rg.taskContextRecord(ctx, task, f, domain, spec)
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) {
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 + "."
Expand All @@ -418,11 +451,11 @@ func (rg *RecordGenerator) taskContextRecord(ctx context, task state.Task, f sta
canonical := ctx.taskName + "-" + ctx.taskID + "-" + ctx.slaveID + "." + fname
arec := ctx.taskName + "." + fname

rg.insertRR(arec+tail, ctx.taskIP, "A")
rg.insertRR(canonical+tail, ctx.taskIP, "A")
rg.insertTaskRR(arec+tail, ctx.taskIP, "A", enumTask)
rg.insertTaskRR(canonical+tail, ctx.taskIP, "A", enumTask)

rg.insertRR(arec+".slave"+tail, ctx.slaveIP, "A")
rg.insertRR(canonical+".slave"+tail, ctx.slaveIP, "A")
rg.insertTaskRR(arec+".slave"+tail, ctx.slaveIP, "A", enumTask)
rg.insertTaskRR(canonical+".slave"+tail, ctx.slaveIP, "A", enumTask)

// Add RFC 2782 SRV records
slaveHost := canonical + ".slave" + tail
Expand All @@ -432,12 +465,12 @@ func (rg *RecordGenerator) taskContextRecord(ctx context, task state.Task, f sta
slaveTarget := slaveHost + ":" + port

if !task.HasDiscoveryInfo() {
rg.insertRR(tcpName+tail, slaveTarget, "SRV")
rg.insertRR(udpName+tail, slaveTarget, "SRV")
rg.insertTaskRR(tcpName+tail, slaveTarget, "SRV", enumTask)
rg.insertTaskRR(udpName+tail, slaveTarget, "SRV", enumTask)
}

rg.insertRR(tcpName+".slave"+tail, slaveTarget, "SRV")
rg.insertRR(udpName+".slave"+tail, slaveTarget, "SRV")
rg.insertTaskRR(tcpName+".slave"+tail, slaveTarget, "SRV", enumTask)
rg.insertTaskRR(udpName+".slave"+tail, slaveTarget, "SRV", enumTask)
}

if !task.HasDiscoveryInfo() {
Expand All @@ -451,10 +484,10 @@ func (rg *RecordGenerator) taskContextRecord(ctx context, task state.Task, f sta
proto := spec(port.Protocol)
if proto != "" {
name := "_" + ctx.taskName + "._" + proto + "." + fname
rg.insertRR(name+tail, target, "SRV")
rg.insertTaskRR(name+tail, target, "SRV", enumTask)
} else {
rg.insertRR(tcpName+tail, target, "SRV")
rg.insertRR(udpName+tail, target, "SRV")
rg.insertTaskRR(tcpName+tail, target, "SRV", enumTask)
rg.insertTaskRR(udpName+tail, target, "SRV", enumTask)
}
}

Expand Down Expand Up @@ -528,6 +561,11 @@ func (rg *RecordGenerator) exists(name, host, rtype string) bool {
// 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, rtype string, enumTask *EnumerableTask) bool {
enumRecord := EnumerableRecord{Name: name, Host: host, Rtype: rtype}
enumTask.Records = append(enumTask.Records, enumRecord)
return rg.insertRR(name, host, rtype)
}
func (rg *RecordGenerator) insertRR(name, host, rtype string) bool {
if host == "" || rg.exists(name, host, rtype) {
return false
Expand Down
12 changes: 12 additions & 0 deletions resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ func (res *Resolver) configureHTTP() {
ws.Route(ws.GET("/v1/hosts/{host}").To(res.RestHost))
ws.Route(ws.GET("/v1/hosts/{host}/ports").To(res.RestPorts))
ws.Route(ws.GET("/v1/services/{service}").To(res.RestService))
if res.config.EnumerationOn {
ws.Route(ws.GET("/v1/enumerate").To(res.RestEnumerate))
}
restful.Add(ws)
}

Expand Down Expand Up @@ -498,6 +501,15 @@ func (res *Resolver) RestConfig(req *restful.Request, resp *restful.Response) {
}
}

// RestEnumerate handles HTTP requests of the enumeration data
func (res *Resolver) RestEnumerate(req *restful.Request, resp *restful.Response) {

enumData := res.records().EnumData
if err := resp.WriteAsJson(enumData); err != nil {
logging.Error.Println(err)
}
}

// RestVersion handles HTTP requests of Mesos-DNS version.
func (res *Resolver) RestVersion(req *restful.Request, resp *restful.Response) {
err := resp.WriteAsJson(map[string]string{
Expand Down

0 comments on commit 6f90aee

Please sign in to comment.