Пример #1
0
func (c *ResourceRecordChangeset) Apply() error {
	ctx := context.Background()
	etcdPathPrefix := c.zone.zones.intf.etcdPathPrefix
	getOpts := &etcdc.GetOptions{}
	setOpts := &etcdc.SetOptions{}
	deleteOpts := &etcdc.DeleteOptions{
		Recursive: true,
	}

	for _, changeset := range c.changeset {
		switch changeset.cstype {
		case ADDITION:
			for _, rrdata := range changeset.rrset.Rrdatas() {
				b, err := json.Marshal(&dnsmsg.Service{Host: rrdata, TTL: uint32(changeset.rrset.Ttl()), Group: changeset.rrset.Name()})
				if err != nil {
					return err
				}
				recordValue := string(b)
				recordLabel := getHash(rrdata)
				recordKey := buildDNSNameString(changeset.rrset.Name(), recordLabel)

				response, err := c.zone.zones.intf.etcdKeysAPI.Get(ctx, dnsmsg.Path(recordKey, etcdPathPrefix), getOpts)
				if err == nil && response != nil {
					return fmt.Errorf("Key already exist, key: %v", recordKey)
				}

				_, err = c.zone.zones.intf.etcdKeysAPI.Set(ctx, dnsmsg.Path(recordKey, etcdPathPrefix), recordValue, setOpts)
				if err != nil {
					return err
				}
			}
		case DELETION:
			for _, rrdata := range changeset.rrset.Rrdatas() {
				recordLabel := getHash(rrdata)
				recordKey := buildDNSNameString(changeset.rrset.Name(), recordLabel)
				_, err := c.zone.zones.intf.etcdKeysAPI.Delete(ctx, dnsmsg.Path(recordKey, etcdPathPrefix), deleteOpts)
				if err != nil {
					return err
				}
			}
			// TODO: We need to cleanup empty dirs in etcd
		}
	}
	return nil
}
Пример #2
0
// Records looks up records in etcd. If exact is true, it will lookup just
// this name. This is used when find matches when completing SRV lookups
// for instance.
func (g Etcd) Records(name string, exact bool) ([]msg.Service, error) {
	path, star := msg.PathWithWildcard(name, g.PathPrefix)
	r, err := g.Get(path, true)
	if err != nil {
		return nil, err
	}
	segments := strings.Split(msg.Path(name, g.PathPrefix), "/")
	switch {
	case exact && r.Node.Dir:
		return nil, nil
	case r.Node.Dir:
		return g.loopNodes(r.Node.Nodes, segments, star, nil)
	default:
		return g.loopNodes([]*etcdc.Node{r.Node}, segments, false, nil)
	}
}
Пример #3
0
func (rrsets ResourceRecordSets) Get(name string) (dnsprovider.ResourceRecordSet, error) {
	getOpts := &etcdc.GetOptions{
		Recursive: true,
	}
	etcdPathPrefix := rrsets.zone.zones.intf.etcdPathPrefix
	response, err := rrsets.zone.zones.intf.etcdKeysAPI.Get(context.Background(), dnsmsg.Path(name, etcdPathPrefix), getOpts)
	if err != nil {
		if etcdc.IsKeyNotFound(err) {
			glog.V(2).Infof("Subdomain %q does not exist", name)
			return nil, nil
		}
		return nil, fmt.Errorf("Failed to get service from etcd, err: %v", err)
	}
	if emptyResponse(response) {
		glog.V(2).Infof("Subdomain %q does not exist in etcd", name)
		return nil, nil
	}

	rrset := ResourceRecordSet{name: name, rrdatas: []string{}, rrsets: &rrsets}
	found := false
	for _, node := range response.Node.Nodes {
		found = true
		service := dnsmsg.Service{}
		err = json.Unmarshal([]byte(node.Value), &service)
		if err != nil {
			return nil, fmt.Errorf("Failed to unmarshall json data, err: %v", err)
		}

		// assuming all rrdatas in a rrset will have same type
		ip := net.ParseIP(service.Host)
		switch {
		case ip == nil:
			rrset.rrsType = rrstype.CNAME
		case ip.To4() != nil:
			rrset.rrsType = rrstype.A
		}
		rrset.rrdatas = append(rrset.rrdatas, service.Host)
		rrset.ttl = int64(service.TTL)
	}

	if !found {
		return nil, nil
	}

	return rrset, nil
}