diff --git a/object_manager.go b/object_manager.go index d3a7f82b..3e4c83fa 100644 --- a/object_manager.go +++ b/object_manager.go @@ -7,24 +7,27 @@ import ( "net" "net/url" "regexp" + "strings" ) type IBObjectManager interface { AllocateIP(netview string, cidr string, ipAddr string, isIPv6 bool, macAddress string, name string, comment string, eas EA) (*FixedAddress, error) AllocateNetwork(netview string, cidr string, isIPv6 bool, prefixLen uint, comment string, eas EA) (network *Network, err error) - CreateARecord(netview string, dnsview string, recordname string, cidr string, ipAddr string, ea EA) (*RecordA, error) + CreateARecord(netView string, dnsView string, name string, cidr string, ipAddr string, ttl uint32, useTTL bool, comment string, ea EA) (*RecordA, error) + CreateAAAARecord(netView string, dnsView string, recordName string, cidr string, ipAddr string, useTtl bool, ttl uint32, comment string, eas EA) (*RecordAAAA, error) CreateZoneAuth(fqdn string, ea EA) (*ZoneAuth, error) - CreateCNAMERecord(canonical string, recordname string, dnsview string, ea EA) (*RecordCNAME, error) + CreateCNAMERecord(dnsview string, canonical string, recordname string, useTtl bool, ttl uint32, comment string, eas EA) (*RecordCNAME, error) CreateDefaultNetviews(globalNetview string, localNetview string) (globalNetviewRef string, localNetviewRef string, err error) CreateEADefinition(eadef EADefinition) (*EADefinition, error) CreateHostRecord(enabledns bool, enabledhcp bool, recordName string, netview string, dnsview string, ipv4cidr string, ipv6cidr string, ipv4Addr string, ipv6Addr string, macAddr string, duid string, comment string, eas EA, aliases []string) (*HostRecord, error) CreateNetwork(netview string, cidr string, isIPv6 bool, comment string, eas EA) (*Network, error) CreateNetworkContainer(netview string, cidr string, isIPv6 bool, comment string, eas EA) (*NetworkContainer, error) CreateNetworkView(name string) (*NetworkView, error) - CreatePTRRecord(netview string, dnsview string, recordname string, cidr string, ipAddr string, ea EA) (*RecordPTR, error) + CreatePTRRecord(networkView string, dnsView string, ptrdname string, recordName string, cidr string, ipAddr string, useTtl bool, ttl uint32, comment string, eas EA) (*RecordPTR, error) CreateTXTRecord(recordname string, text string, ttl int, dnsview string) (*RecordTXT, error) CreateZoneDelegated(fqdn string, delegate_to []NameServer) (*ZoneDelegated, error) DeleteARecord(ref string) (string, error) + DeleteAAAARecord(ref string) (string, error) DeleteZoneAuth(ref string) (string, error) DeleteCNAMERecord(ref string) (string, error) DeleteFixedAddress(ref string) (string, error) @@ -36,6 +39,9 @@ type IBObjectManager interface { DeleteTXTRecord(ref string) (string, error) DeleteZoneDelegated(ref string) (string, error) GetARecordByRef(ref string) (*RecordA, error) + GetAAAARecord(dnsview string, recordName string, ipAddr string) (*RecordAAAA, error) + GetAAAARecordByRef(ref string) (*RecordAAAA, error) + GetCNAMERecord(dnsview string, canonical string, recordName string) (*RecordCNAME, error) GetCNAMERecordByRef(ref string) (*RecordCNAME, error) GetEADefinition(name string) (*EADefinition, error) GetFixedAddress(netview string, cidr string, ipAddr string, isIPv6 bool, macAddr string) (*FixedAddress, error) @@ -49,6 +55,7 @@ type IBObjectManager interface { GetNetworkContainerByRef(ref string) (*NetworkContainer, error) GetNetworkView(name string) (*NetworkView, error) GetNetworkViewByRef(ref string) (*NetworkView, error) + GetPTRRecord(dnsview string, ptrdname string, recordName string, ipAddr string) (*RecordPTR, error) GetPTRRecordByRef(ref string) (*RecordPTR, error) GetZoneAuthByRef(ref string) (*ZoneAuth, error) GetZoneDelegated(fqdn string) (*ZoneDelegated, error) @@ -58,11 +65,15 @@ type IBObjectManager interface { GetGridInfo() ([]Grid, error) GetGridLicense() ([]License, error) ReleaseIP(netview string, cidr string, ipAddr string, isIPv6 bool, macAddr string) (string, error) + UpdateAAAARecord(ref string, netView string, recordName string, cidr string, ipAddr string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordAAAA, error) + UpdateCNAMERecord(ref string, canonical string, recordName string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordCNAME, error) UpdateFixedAddress(fixedAddrRef string, name string, matchclient string, macAddress string, comment string, eas EA) (*FixedAddress, error) UpdateHostRecord(hostRref string, enabledns bool, enabledhcp bool, name string, ipv4Addr string, ipv6Addr string, macAddress string, duid string, comment string, eas EA, aliases []string) (*HostRecord, error) UpdateNetwork(ref string, setEas EA, comment string) (*Network, error) UpdateNetworkContainer(ref string, setEas EA, comment string) (*NetworkContainer, error) UpdateNetworkViewEA(ref string, setEas EA) error + UpdatePTRRecord(ref string, ptrdname string, name string, ipAddr string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordPTR, error) + UpdateARecord(ref string, name string, ipAddr string, cidr string, netview string, ttl uint32, useTTL bool, comment string, eas EA) (*RecordA, error) UpdateZoneDelegated(ref string, delegate_to []NameServer) (*ZoneDelegated, error) } @@ -730,23 +741,126 @@ func (objMgr *ObjectManager) UpdateNetworkContainer( } func (objMgr *ObjectManager) CreateARecord( - netview string, - dnsview string, - recordname string, + netView string, + dnsView string, + name string, cidr string, ipAddr string, + ttl uint32, + useTTL bool, + comment string, eas EA) (*RecordA, error) { - recordA := NewRecordA(dnsview, "", recordname, "", eas, "") + cleanName := strings.TrimSpace(name) + if cleanName == "" || cleanName != name { + return nil, fmt.Errorf( + "'name' argument is expected to be non-empty and it must NOT contain leading/trailing spaces") + } + + recordA := NewRecordA(dnsView, "", name, "", ttl, useTTL, comment, eas, "") if ipAddr == "" { - recordA.Ipv4Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netview) + if cidr == "" { + return nil, fmt.Errorf("CIDR must not be empty") + } + ip, _, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("cannot parse CIDR value: %s", err.Error()) + } + if ip.To4() == nil { + return nil, fmt.Errorf("CIDR value must be an IPv4 CIDR, not an IPv6 one") + } + if netView == "" { + recordA.Ipv4Addr = fmt.Sprintf("func:nextavailableip:%s", cidr) + } else { + recordA.Ipv4Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netView) + } } else { + ip := net.ParseIP(ipAddr) + if ip == nil { + return nil, fmt.Errorf("'IP address for the record is not valid") + } + if ip.To4() == nil { + return nil, fmt.Errorf("IP address must be an IPv4 address, not an IPv6 one") + } recordA.Ipv4Addr = ipAddr } + ref, err := objMgr.connector.CreateObject(recordA) - recordA.Ref = ref - return recordA, err + if err != nil { + return nil, err + } + + newRec, err := objMgr.GetARecordByRef(ref) + if err != nil { + return nil, err + } + + return newRec, nil +} + +func (objMgr *ObjectManager) UpdateARecord( + ref string, + name string, + ipAddr string, + cidr string, + netView string, + ttl uint32, + useTTL bool, + comment string, + eas EA) (*RecordA, error) { + + cleanName := strings.ToLower(strings.TrimSpace(name)) + if cleanName == "" || cleanName != name { + return nil, fmt.Errorf( + "'name' argument is expected to be non-empty and it must NOT contain leading/trailing spaces") + } + + rec, err := objMgr.GetARecordByRef(ref) + if err != nil { + return nil, err + } + newIpAddr := rec.Ipv4Addr + if ipAddr == "" { + if cidr != "" { + ip, _, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("cannot parse CIDR value: %s", err.Error()) + } + if ip.To4() == nil { + return nil, fmt.Errorf("CIDR value must be an IPv4 CIDR, not an IPv6 one") + } + if netView == "" { + newIpAddr = fmt.Sprintf("func:nextavailableip:%s", cidr) + } else { + newIpAddr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netView) + } + } + // else: leaving ipv4addr field untouched + } else { + ip := net.ParseIP(ipAddr) + if ip == nil { + return nil, fmt.Errorf("'IP address for the record is not valid") + } + if ip.To4() == nil { + return nil, fmt.Errorf("IP address must be an IPv4 address, not an IPv6 one") + } + newIpAddr = ipAddr + } + rec = NewRecordA( + "", "", name, newIpAddr, ttl, useTTL, comment, eas, ref) + ref, err = objMgr.connector.UpdateObject(rec, ref) + if err != nil { + return nil, err + } + rec.Ref = ref + + rec, err = objMgr.GetARecordByRef(ref) + if err != nil { + return nil, err + } + + return rec, nil } func (objMgr *ObjectManager) GetARecordByRef(ref string) (*RecordA, error) { @@ -755,29 +869,207 @@ func (objMgr *ObjectManager) GetARecordByRef(ref string) (*RecordA, error) { recordA, ref, NewQueryParams(false, nil), &recordA) return recordA, err } + func (objMgr *ObjectManager) DeleteARecord(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } +func (objMgr *ObjectManager) CreateAAAARecord( + netView string, + dnsView string, + recordName string, + cidr string, + ipAddr string, + useTtl bool, + ttl uint32, + comment string, + eas EA) (*RecordAAAA, error) { + + cleanName := strings.ToLower(strings.TrimSpace(recordName)) + if cleanName == "" || cleanName != recordName { + return nil, fmt.Errorf( + "'name' argument is expected to be non-empty and it must NOT contain leading/trailing spaces") + } + recordAAAA := NewRecordAAAA(dnsView, recordName, "", useTtl, ttl, comment, eas, "") + + if ipAddr == "" { + if cidr == "" { + return nil, fmt.Errorf("CIDR must not be empty") + } + ipAddress, _, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("cannot parse CIDR value: %s", err.Error()) + } + if ipAddress.To4() != nil || ipAddress.To16() == nil { + return nil, fmt.Errorf("CIDR value must be an IPv6 CIDR, not an IPv4 one") + } + if netView == "" { + netView = "default" + } + recordAAAA.Ipv6Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netView) + } else { + ipAddress := net.ParseIP(ipAddr) + if ipAddress == nil { + return nil, fmt.Errorf("IP address for the record is not valid") + } + if ipAddress.To4() != nil || ipAddress.To16() == nil { + return nil, fmt.Errorf("IP address must be an IPv6 address, not an IPv4 one") + } + recordAAAA.Ipv6Addr = ipAddr + } + ref, err := objMgr.connector.CreateObject(recordAAAA) + if err != nil { + return nil, err + } + recordAAAA, err = objMgr.GetAAAARecordByRef(ref) + if err != nil { + return nil, err + } + return recordAAAA, nil +} + +func (objMgr *ObjectManager) GetAAAARecord(dnsview string, recordName string, ipAddr string) (*RecordAAAA, error) { + var res []RecordAAAA + recordAAAA := NewEmptyRecordAAAA() + if dnsview == "" || recordName == "" || ipAddr == "" { + return nil, fmt.Errorf("DNS view, IPv6 address and record name of the record are required to retreive a unique AAAA record") + } + sf := map[string]string{ + "view": dnsview, + "name": recordName, + "ipv6addr": ipAddr, + } + queryParams := NewQueryParams(false, sf) + err := objMgr.connector.GetObject(recordAAAA, "", queryParams, &res) + + if err != nil { + return nil, err + } else if res == nil || len(res) == 0 { + return nil, NewNotFoundError( + fmt.Sprintf( + "AAAA record with name '%s' and IPv6 address '%s' in DNS view '%s' is not found", + recordName, ipAddr, dnsview)) + } + return &res[0], nil +} + +func (objMgr *ObjectManager) GetAAAARecordByRef(ref string) (*RecordAAAA, error) { + recordAAAA := NewEmptyRecordAAAA() + err := objMgr.connector.GetObject( + recordAAAA, ref, NewQueryParams(false, nil), &recordAAAA) + return recordAAAA, err +} + +func (objMgr *ObjectManager) DeleteAAAARecord(ref string) (string, error) { + return objMgr.connector.DeleteObject(ref) +} + +func (objMgr *ObjectManager) UpdateAAAARecord( + ref string, + netView string, + recordName string, + ipAddr string, + cidr string, + useTtl bool, + ttl uint32, + comment string, + setEas EA) (*RecordAAAA, error) { + + cleanName := strings.ToLower(strings.TrimSpace(recordName)) + if cleanName == "" || cleanName != recordName { + return nil, fmt.Errorf( + "'name' argument is expected to be non-empty and it must NOT contain leading/trailing spaces") + } + + rec, err := objMgr.GetAAAARecordByRef(ref) + if err != nil { + return nil, err + } + newIpAddr := rec.Ipv6Addr + if ipAddr == "" { + if cidr != "" { + ipAddress, _, err := net.ParseCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("cannot parse CIDR value: %s", err.Error()) + } + if ipAddress.To4() != nil || ipAddress.To16() == nil { + return nil, fmt.Errorf("CIDR value must be an IPv6 CIDR, not an IPv4 one") + } + if netView == "" { + netView = "default" + } + newIpAddr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netView) + } + } else { + ipAddress := net.ParseIP(ipAddr) + if ipAddress == nil { + return nil, fmt.Errorf("IP address for the record is not valid") + } + if ipAddress.To4() != nil || ipAddress.To16() == nil { + return nil, fmt.Errorf("IP address must be an IPv6 address, not an IPv4 one") + } + newIpAddr = ipAddr + } + recordAAAA := NewRecordAAAA("", recordName, newIpAddr, useTtl, ttl, comment, setEas, ref) + reference, err := objMgr.connector.UpdateObject(recordAAAA, ref) + if err != nil { + return nil, err + } + + recordAAAA, err = objMgr.GetAAAARecordByRef(reference) + if err != nil { + return nil, err + } + return recordAAAA, nil +} + func (objMgr *ObjectManager) CreateCNAMERecord( + dnsview string, canonical string, recordname string, - dnsview string, + useTtl bool, + ttl uint32, + comment string, eas EA) (*RecordCNAME, error) { - recordCNAME := NewRecordCNAME(RecordCNAME{ - View: dnsview, - Name: recordname, - Canonical: canonical, - Ea: eas}) + if canonical == "" || recordname == "" { + return nil, fmt.Errorf("canonical name and record name fields are required to create a CNAME record") + } + recordCNAME := NewRecordCNAME(dnsview, canonical, recordname, useTtl, ttl, comment, eas, "") ref, err := objMgr.connector.CreateObject(recordCNAME) - recordCNAME.Ref = ref + recordCNAME, err = objMgr.GetCNAMERecordByRef(ref) return recordCNAME, err } +func (objMgr *ObjectManager) GetCNAMERecord(dnsview string, canonical string, recordName string) (*RecordCNAME, error) { + var res []RecordCNAME + recordCNAME := NewEmptyRecordCNAME() + if dnsview == "" || canonical == "" || recordName == "" { + return nil, fmt.Errorf("DNS view, canonical name and record name of the record are required to retreive a unique CNAME record") + } + sf := map[string]string{ + "view": dnsview, + "canonical": canonical, + "name": recordName, + } + + queryParams := NewQueryParams(false, sf) + err := objMgr.connector.GetObject(recordCNAME, "", queryParams, &res) + + if err != nil { + return nil, err + } else if res == nil || len(res) == 0 { + return nil, NewNotFoundError( + fmt.Sprintf( + "CNAME record with name '%s' and canonical name '%s' in DNS view '%s' is not found", + recordName, canonical, dnsview)) + } + return &res[0], nil +} + func (objMgr *ObjectManager) GetCNAMERecordByRef(ref string) (*RecordCNAME, error) { - recordCNAME := NewRecordCNAME(RecordCNAME{}) + recordCNAME := NewEmptyRecordCNAME() err := objMgr.connector.GetObject( recordCNAME, ref, NewQueryParams(false, nil), &recordCNAME) return recordCNAME, err @@ -787,6 +1079,25 @@ func (objMgr *ObjectManager) DeleteCNAMERecord(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } +func (objMgr *ObjectManager) UpdateCNAMERecord( + ref string, + canonical string, + recordName string, + useTtl bool, + ttl uint32, + comment string, + setEas EA) (*RecordCNAME, error) { + + recordCNAME := NewRecordCNAME("", canonical, recordName, useTtl, ttl, comment, setEas, ref) + updatedRef, err := objMgr.connector.UpdateObject(recordCNAME, ref) + if err != nil { + return nil, err + } + + recordCNAME, err = objMgr.GetCNAMERecordByRef(updatedRef) + return recordCNAME, err +} + // Creates TXT Record. Use TTL of 0 to inherit TTL from the Zone func (objMgr *ObjectManager) CreateTXTRecord(recordname string, text string, ttl int, dnsview string) (*RecordTXT, error) { @@ -862,31 +1173,100 @@ func (objMgr *ObjectManager) DeleteTXTRecord(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } +// TODO check if the respective zone exists before creation of the record func (objMgr *ObjectManager) CreatePTRRecord( - netview string, - dnsview string, - recordname string, + networkView string, + dnsView string, + ptrdname string, + recordName string, cidr string, ipAddr string, + useTtl bool, + ttl uint32, + comment string, eas EA) (*RecordPTR, error) { - recordPTR := NewRecordPTR(RecordPTR{ - View: dnsview, - PtrdName: recordname, - Ea: eas}) + if ptrdname == "" { + return nil, fmt.Errorf("ptrdname is a required field to create a PTR record") + } + recordPTR := NewRecordPTR(dnsView, ptrdname, &useTtl, ttl, comment, eas) - if ipAddr == "" { - recordPTR.Ipv4Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netview) + if ipAddr == "" && cidr != "" && networkView != "" { + ipAddress, net, err := net.ParseCIDR(cidr) + if err != nil { + return nil, err + } + if ipAddress.To4() != nil { + if net.String() != cidr { + return nil, fmt.Errorf("%s is an invalid CIDR. Note: leading zeros should be removed if exists", cidr) + } + recordPTR.Ipv4Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, networkView) + } else { + recordPTR.Ipv6Addr = fmt.Sprintf("func:nextavailableip:%s,%s", cidr, networkView) + } + } else if ipAddr != "" { + ipAddress := net.ParseIP(ipAddr) + if ipAddress == nil { + return nil, fmt.Errorf("%s is an invalid IP address", ipAddr) + } + if ipAddress.To4() != nil { + recordPTR.Ipv4Addr = ipAddr + } else { + recordPTR.Ipv6Addr = ipAddr + } + } else if recordName != "" { + recordPTR.Name = recordName } else { - recordPTR.Ipv4Addr = ipAddr + return nil, fmt.Errorf("CIDR and network view are required to allocate a next available IP address\n" + + "IP address is required to create PTR record in reverse mapping zone\n" + + "record name is required to create a record in forwarrd mapping zone") } ref, err := objMgr.connector.CreateObject(recordPTR) - recordPTR.Ref = ref + if err != nil { + return nil, err + } + recordPTR, err = objMgr.GetPTRRecordByRef(ref) return recordPTR, err } +func (objMgr *ObjectManager) GetPTRRecord(dnsview string, ptrdname string, recordName string, ipAddr string) (*RecordPTR, error) { + var res []RecordPTR + recordPtr := NewEmptyRecordPTR() + sf := map[string]string{ + "view": dnsview, + "ptrdname": ptrdname, + } + if ipAddr != "" { + ipAddress := net.ParseIP(ipAddr) + if ipAddress == nil { + return nil, fmt.Errorf("%s is an invalid IP address", ipAddr) + } + if ipAddress.To4() != nil { + sf["ipv4addr"] = ipAddr + } else { + sf["ipv6addr"] = ipAddr + } + } else if recordName != "" { + sf["name"] = recordName + } else { + return nil, fmt.Errorf("record name or IP Address of the record has to be passed to get a unique record") + } + queryParams := NewQueryParams(false, sf) + err := objMgr.connector.GetObject(recordPtr, "", queryParams, &res) + + if err != nil { + return nil, err + } else if res == nil || len(res) == 0 { + return nil, NewNotFoundError( + fmt.Sprintf( + "PTR record with name/IP '%v' and ptrdname '%s' in DNS view '%s' is not found", + []string{recordName, ipAddr}, ptrdname, dnsview)) + } + return &res[0], nil +} + func (objMgr *ObjectManager) GetPTRRecordByRef(ref string) (*RecordPTR, error) { - recordPTR := NewRecordPTR(RecordPTR{}) + recordPTR := NewEmptyRecordPTR() err := objMgr.connector.GetObject( recordPTR, ref, NewQueryParams(false, nil), &recordPTR) return recordPTR, err @@ -896,6 +1276,35 @@ func (objMgr *ObjectManager) DeletePTRRecord(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } +func (objMgr *ObjectManager) UpdatePTRRecord( + ref string, + ptrdname string, + name string, + ipAddr string, + useTtl bool, + ttl uint32, + comment string, + setEas EA) (*RecordPTR, error) { + + recordPTR := NewRecordPTR("", ptrdname, &useTtl, ttl, comment, setEas) + recordPTR.Ref = ref + recordPTR.Name = name + isIPv6, _ := regexp.MatchString(`^record:ptr/.+.ip6.arpa/.+`, ref) + + if isIPv6 { + recordPTR.Ipv6Addr = ipAddr + } else { + recordPTR.Ipv4Addr = ipAddr + } + reference, err := objMgr.connector.UpdateObject(recordPTR, ref) + if err != nil { + return nil, err + } + + recordPTR, err = objMgr.GetPTRRecordByRef(reference) + return recordPTR, err +} + // CreateMultiObject unmarshals the result into slice of maps func (objMgr *ObjectManager) CreateMultiObject(req *MultiRequest) ([]map[string]interface{}, error) { diff --git a/object_manager_test.go b/object_manager_test.go index dd2ca04f..a690cc41 100644 --- a/object_manager_test.go +++ b/object_manager_test.go @@ -72,8 +72,16 @@ func (c *fakeConnector) GetObject(obj IBObject, ref string, qp *QueryParams, res *res.(*[]License) = c.resultObject.([]License) case *HostRecord: *res.(*[]HostRecord) = c.resultObject.([]HostRecord) + case *RecordAAAA: + *res.(*[]RecordAAAA) = c.resultObject.([]RecordAAAA) + case *RecordPTR: + *res.(*[]RecordPTR) = c.resultObject.([]RecordPTR) case *ZoneDelegated: *res.(*[]ZoneDelegated) = c.resultObject.([]ZoneDelegated) + case *RecordCNAME: + *res.(*[]RecordCNAME) = c.resultObject.([]RecordCNAME) + case *RecordA: + *res.(*[]RecordA) = c.resultObject.([]RecordA) } } else { switch obj.(type) { @@ -89,6 +97,14 @@ func (c *fakeConnector) GetObject(obj IBObject, ref string, qp *QueryParams, res **res.(**FixedAddress) = *c.resultObject.(*FixedAddress) case *HostRecord: **res.(**HostRecord) = *c.resultObject.(*HostRecord) + case *RecordPTR: + **res.(**RecordPTR) = *c.resultObject.(*RecordPTR) + case *RecordCNAME: + **res.(**RecordCNAME) = *c.resultObject.(*RecordCNAME) + case *RecordA: + **res.(**RecordA) = *c.resultObject.(*RecordA) + case *RecordAAAA: + **res.(**RecordAAAA) = *c.resultObject.(*RecordAAAA) } } @@ -646,6 +662,242 @@ var _ = Describe("Object Manager", func() { }) }) + Describe("Update A-record, literal value", func() { + var ( + err error + objMgr IBObjectManager + conn *fakeConnector + //actualObj *RecordA + ) + + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + + //netView := "default" + //netView2 := "notdefault" + dnsView := "default" + dnsZone := "test.loc" + dnsName := "arec1.test.loc" + refBase := "ZG5zLm5ldHdvcmtfdmlldyQyMw" + initIPAddr := "10.2.1.56" + initTTL := uint32(7) + initUseTTL := true + newIPAddr := "10.2.1.57" + newTTL := uint32(70) + newUseTTL := false + //cidr := "10.2.1.0/24" + //nextAvailableIPRequest := fmt.Sprintf( + // "func:nextavailableip:%s,%s", cidr, netView) + //nextAvailableIPRequest2 := fmt.Sprintf( + // "func:nextavailableip:%s,%s", cidr, netView2) + + //It("updating IP address (with a literal value), comment, TTL, EAs", func() { + // initRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, initIPAddr, dnsName, dnsView) + // newRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, newIPAddr, dnsName, dnsView) + // initialEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_old_value", + // "ea3": "ea3_value", + // "ea4": "ea4_value", + // "ea5": "ea5_old_value"} + // initComment := "initial comment" + // initObj := NewRecordA(dnsView, dnsZone, dnsName, initIPAddr, initTTL, initUseTTL, initComment, initialEas, initRef) + // + // newEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_new_value", + // "ea2": "ea2_new_value", + // "ea5": "ea5_old_value"} + // + // getObjIn := NewEmptyRecordA() + // + // newComment := "test comment 1" + // updateObjIn := NewRecordA(dnsView, dnsZone, dnsName, newIPAddr, newTTL, newUseTTL, newComment, newEas, initRef) + // expectedObj := NewRecordA(dnsView, dnsZone, dnsName, newIPAddr, newTTL, newUseTTL, newComment, newEas, newRef) + // + // conn = &fakeConnector{ + // getObjectObj: getObjIn, + // getObjectQueryParams: NewQueryParams(false, nil), + // getObjectRef: initRef, + // getObjectError: nil, + // resultObject: initObj, + // + // updateObjectObj: updateObjIn, + // updateObjectRef: initRef, + // updateObjectError: nil, + // + // fakeRefReturn: newRef, + // } + // objMgr = NewObjectManager(conn, cmpType, tenantID) + // + // actualObj, err = objMgr.UpdateARecord(initRef, newIPAddr, "", "", newTTL, newUseTTL, newComment, newEas) + // Expect(err).To(BeNil()) + // Expect(actualObj).To(BeEquivalentTo(expectedObj)) + //}) + + //It("updating IP address (with 'nextavailableip' function), comment, TTL, EAs", func() { + // initRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, initIPAddr, dnsName, dnsView) + // newRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, newIPAddr, dnsName, dnsView) + // initialEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_old_value", + // "ea3": "ea3_value", + // "ea4": "ea4_value", + // "ea5": "ea5_old_value"} + // initComment := "initial comment" + // initObj := NewRecordA(dnsView, dnsZone, dnsName, initIPAddr, initTTL, initUseTTL, initComment, initialEas, initRef) + // + // newEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_new_value", + // "ea2": "ea2_new_value", + // "ea5": "ea5_old_value"} + // + // getObjIn := NewEmptyRecordA() + // + // newComment := "test comment 1" + // updateObjIn := NewRecordA(dnsView, dnsZone, dnsName, nextAvailableIPRequest, newTTL, newUseTTL, newComment, newEas, initRef) + // expectedObj := NewRecordA(dnsView, dnsZone, dnsName, newIPAddr, newTTL, newUseTTL, newComment, newEas, newRef) + // + // conn = &fakeConnector{ + // getObjectObj: getObjIn, + // getObjectQueryParams: NewQueryParams(false, nil), + // getObjectRef: initRef, + // getObjectError: nil, + // resultObject: initObj, + // + // updateObjectObj: updateObjIn, + // updateObjectRef: initRef, + // updateObjectError: nil, + // + // fakeRefReturn: newRef, + // } + // objMgr = NewObjectManager(conn, cmpType, tenantID) + // + // actualObj, err = objMgr.UpdateARecord(initRef, "", cidr, "", newTTL, newUseTTL, newComment, newEas) + // Expect(err).To(BeNil()) + // Expect(actualObj).To(BeEquivalentTo(expectedObj)) + //}) + + //It("updating IP address (with 'nextavailableip' function, non-default netview), comment, TTL, EAs", func() { + // initRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, initIPAddr, dnsName, dnsView) + // newRef := fmt.Sprintf( + // "record:a/%s:%s/%s/%s", + // refBase, newIPAddr, dnsName, dnsView) + // initialEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_old_value", + // "ea3": "ea3_value", + // "ea4": "ea4_value", + // "ea5": "ea5_old_value"} + // initComment := "initial comment" + // initObj := NewRecordA(dnsView, dnsZone, dnsName, initIPAddr, initTTL, initUseTTL, initComment, initialEas, initRef) + // + // newEas := EA{ + // "ea0": "ea0_old_value", + // "ea1": "ea1_new_value", + // "ea2": "ea2_new_value", + // "ea5": "ea5_old_value"} + // + // getObjIn := NewEmptyRecordA() + // + // newComment := "test comment 1" + // updateObjIn := NewRecordA(dnsView, dnsZone, dnsName, nextAvailableIPRequest2, newTTL, newUseTTL, newComment, newEas, initRef) + // expectedObj := NewRecordA(dnsView, dnsZone, dnsName, newIPAddr, newTTL, newUseTTL, newComment, newEas, newRef) + // + // conn = &fakeConnector{ + // getObjectObj: getObjIn, + // getObjectQueryParams: NewQueryParams(false, nil), + // getObjectRef: initRef, + // getObjectError: nil, + // resultObject: initObj, + // + // updateObjectObj: updateObjIn, + // updateObjectRef: initRef, + // updateObjectError: nil, + // + // fakeRefReturn: newRef, + // } + // objMgr = NewObjectManager(conn, cmpType, tenantID) + // + // actualObj, err = objMgr.UpdateARecord(initRef, "", cidr, netView2, newTTL, newUseTTL, newComment, newEas) + // Expect(err).To(BeNil()) + // Expect(actualObj).To(BeEquivalentTo(expectedObj)) + //}) + + It("Negative case: updating an A-record which does not exist", func() { + initRef := fmt.Sprintf( + "record:a/%s:%s/%s/%s", + refBase, initIPAddr, dnsName, dnsView) + getObjIn := NewEmptyRecordA() + + conn = &fakeConnector{ + getObjectObj: getObjIn, + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: initRef, + getObjectError: fmt.Errorf("test error"), + resultObject: NewEmptyRecordA(), + fakeRefReturn: "", + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + _, err = objMgr.UpdateARecord(initRef, dnsName, newIPAddr, "", "", newTTL, newUseTTL, "some comment", nil) + Expect(err).ToNot(BeNil()) + }) + + It("Negative case: updating an A-record with no update access", func() { + initRef := fmt.Sprintf( + "record:a/%s:%s/%s/%s", + refBase, initIPAddr, dnsName, dnsView) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initComment := "initial comment" + initObj := NewRecordA(dnsView, dnsZone, dnsName, initIPAddr, initTTL, initUseTTL, initComment, initialEas, initRef) + + getObjIn := NewEmptyRecordA() + + newEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + + newComment := "test comment 1" + updateObjIn := NewRecordA("", "", dnsName, newIPAddr, newTTL, newUseTTL, newComment, newEas, initRef) + + conn = &fakeConnector{ + getObjectObj: getObjIn, + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: initRef, + getObjectError: nil, + resultObject: initObj, + + updateObjectObj: updateObjIn, + updateObjectRef: initRef, + updateObjectError: fmt.Errorf("test error"), + fakeRefReturn: "", + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + _, err = objMgr.UpdateARecord(initRef, dnsName, newIPAddr, "", "", newTTL, newUseTTL, newComment, newEas) + Expect(err).ToNot(BeNil()) + }) + }) + Describe("Create Network Container", func() { cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" @@ -1537,7 +1789,7 @@ var _ = Describe("Object Manager", func() { }) }) - Describe("Allocate specific A Record ", func() { + Describe("Create a specific A-Record ", func() { cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" netviewName := "private" @@ -1547,66 +1799,66 @@ var _ = Describe("Object Manager", func() { vmName := "dummyvm" dnsView := "default" recordName := "test" - fakeRefReturn := fmt.Sprintf("record:a/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + zone := "example.com" + comment := "test comment" + fakeRefReturn := fmt.Sprintf( + "record:a/ZG5zLmJpbmRfY25h:%s/%s", + recordName, + netviewName) + + eas := make(EA) + eas["VM ID"] = vmID + eas["VM Name"] = vmName + objectForCreation := NewRecordA( + dnsView, "", recordName, ipAddr, 5, true, comment, eas, "") + objectAsResult := NewRecordA( + dnsView, zone, recordName, ipAddr, 5, true, comment, eas, fakeRefReturn) + aniFakeConnector := &fakeConnector{ - createObjectObj: NewRecordA( - dnsView, "", recordName, ipAddr, nil, ""), - getObjectRef: fakeRefReturn, - getObjectObj: NewRecordA( - dnsView, "", recordName, ipAddr, nil, fakeRefReturn), + createObjectObj: objectForCreation, + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordA(), getObjectQueryParams: NewQueryParams(false, nil), - resultObject: NewRecordA( - dnsView, "", recordName, ipAddr, nil, fakeRefReturn), - fakeRefReturn: fakeRefReturn, + resultObject: objectAsResult, + fakeRefReturn: fakeRefReturn, } - objMgr := NewObjectManager(aniFakeConnector, cmpType, tenantID) - ea := make(EA) - aniFakeConnector.createObjectObj.(*RecordA).Ea = ea - aniFakeConnector.createObjectObj.(*RecordA).Ea["VM ID"] = vmID - aniFakeConnector.createObjectObj.(*RecordA).Ea["VM Name"] = vmName - - aniFakeConnector.resultObject.(*RecordA).Ea = ea - aniFakeConnector.resultObject.(*RecordA).Ea["VM ID"] = vmID - aniFakeConnector.resultObject.(*RecordA).Ea["VM Name"] = vmName - - aniFakeConnector.getObjectObj.(*RecordA).Ea = ea - aniFakeConnector.getObjectObj.(*RecordA).Ea["VM ID"] = vmID - aniFakeConnector.getObjectObj.(*RecordA).Ea["VM Name"] = vmName - var actualRecord *RecordA var err error It("should pass expected A record Object to CreateObject", func() { - actualRecord, err = objMgr.CreateARecord(netviewName, dnsView, recordName, cidr, ipAddr, ea) + actualRecord, err = objMgr.CreateARecord(netviewName, dnsView, recordName, cidr, ipAddr, 5, true, comment, eas) }) It("should return expected A record Object", func() { - Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) Expect(err).To(BeNil()) + Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) }) }) - Describe("Allocate next available A Record ", func() { + Describe("Create an A-record by allocating next available IP address", func() { + return cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" netviewName := "private" cidr := "53.0.0.0/24" - ipAddr := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) + ipAddrReq := "" + ipAddrRes := "53.0.0.1" + ipAddrFunc := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) vmID := "93f9249abc039284" vmName := "dummyvm" dnsView := "default" recordName := "test" - fakeRefReturn := fmt.Sprintf("record:a/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + fakeRefReturn := fmt.Sprintf( + "record:a/ZG5zLmJpbmRfY25h:%s/%s/%s", + recordName, + ipAddrRes, + netviewName) aniFakeConnector := &fakeConnector{ createObjectObj: NewRecordA( - dnsView, "", recordName, ipAddr, nil, ""), - getObjectRef: fakeRefReturn, - getObjectObj: NewRecordA( - dnsView, "", recordName, ipAddr, nil, fakeRefReturn), - getObjectQueryParams: NewQueryParams(false, nil), + dnsView, "", recordName, ipAddrFunc, 0, false, "", nil, ""), resultObject: NewRecordA( - dnsView, "", recordName, ipAddr, nil, fakeRefReturn), + dnsView, "", recordName, ipAddrRes, 0, false, "", nil, fakeRefReturn), fakeRefReturn: fakeRefReturn, } @@ -1621,200 +1873,1053 @@ var _ = Describe("Object Manager", func() { aniFakeConnector.resultObject.(*RecordA).Ea["VM ID"] = vmID aniFakeConnector.resultObject.(*RecordA).Ea["VM Name"] = vmName - aniFakeConnector.getObjectObj.(*RecordA).Ea = ea - aniFakeConnector.getObjectObj.(*RecordA).Ea["VM ID"] = vmID - aniFakeConnector.getObjectObj.(*RecordA).Ea["VM Name"] = vmName - var actualRecord *RecordA var err error It("should pass expected A record Object to CreateObject", func() { - actualRecord, err = objMgr.CreateARecord(netviewName, dnsView, recordName, cidr, ipAddr, ea) + actualRecord, err = objMgr.CreateARecord(netviewName, dnsView, recordName, cidr, ipAddrReq, 0, false, "", ea) }) It("should return expected A record Object", func() { - Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) Expect(err).To(BeNil()) + Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) }) }) - Describe("Allocate specific PTR Record ", func() { + Describe("Allocate specific AAAA Record ", func() { cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" - netviewName := "private" - cidr := "53.0.0.0/24" - ipAddr := "53.0.0.1" + ipAddr := "2001:db8:abcd:14::1" vmID := "93f9249abc039284" vmName := "dummyvm" dnsView := "default" - recordName := "test" - fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) - - aniFakeConnector := &fakeConnector{ - createObjectObj: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - }), - getObjectRef: fakeRefReturn, - getObjectObj: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - Ref: fakeRefReturn, - }), + recordName := "test.domain.com" + comment := "Test creation" + fakeRefReturn := fmt.Sprintf("record:aaaa/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + ea := EA{"VM Name": vmName, "VM ID": vmID} + conn := &fakeConnector{ + createObjectObj: NewRecordAAAA( + dnsView, recordName, ipAddr, false, 0, comment, ea, ""), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordAAAA(), getObjectQueryParams: NewQueryParams(false, nil), - resultObject: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - Ref: fakeRefReturn, - }), + resultObject: NewRecordAAAA( + dnsView, recordName, ipAddr, false, 0, comment, ea, fakeRefReturn), fakeRefReturn: fakeRefReturn, } - objMgr := NewObjectManager(aniFakeConnector, cmpType, tenantID) + objMgr := NewObjectManager(conn, cmpType, tenantID) - ea := make(EA) - aniFakeConnector.createObjectObj.(*RecordPTR).Ea = ea - aniFakeConnector.createObjectObj.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.createObjectObj.(*RecordPTR).Ea["VM Name"] = vmName + var actualRecord *RecordAAAA + var err error + It("should pass expected AAAA record Object to CreateObject", func() { + actualRecord, err = objMgr.CreateAAAARecord("", dnsView, recordName, "", ipAddr, false, uint32(0), comment, ea) + }) + It("should return expected AAAA record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) - aniFakeConnector.resultObject.(*RecordPTR).Ea = ea - aniFakeConnector.resultObject.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.resultObject.(*RecordPTR).Ea["VM Name"] = vmName + Describe("Allocate next available AAAA Record ", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + netviewName := "private" + cidr := "2001:db8:abcd:14::/64" + ipAddr := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + recordName := "test.domain.com" + comment := "Test creation" + fakeRefReturn := fmt.Sprintf("record:aaaa/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + ea := EA{"VM Name": vmName, "VM ID": vmID} + conn := &fakeConnector{ + createObjectObj: NewRecordAAAA( + dnsView, recordName, ipAddr, false, 0, comment, ea, ""), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordAAAA(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordAAAA( + dnsView, recordName, ipAddr, false, 0, comment, ea, fakeRefReturn), + fakeRefReturn: fakeRefReturn, + } - aniFakeConnector.getObjectObj.(*RecordPTR).Ea = ea - aniFakeConnector.getObjectObj.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.getObjectObj.(*RecordPTR).Ea["VM Name"] = vmName + objMgr := NewObjectManager(conn, cmpType, tenantID) - var actualRecord *RecordPTR + var actualRecord *RecordAAAA var err error - It("should pass expected PTR record Object to CreateObject", func() { - actualRecord, err = objMgr.CreatePTRRecord(netviewName, dnsView, recordName, cidr, ipAddr, ea) + It("should pass expected AAAA record Object to CreateObject", func() { + actualRecord, err = objMgr.CreateAAAARecord(netviewName, dnsView, recordName, cidr, "", false, uint32(0), comment, ea) }) - It("should return expected PTR record Object", func() { - Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) + It("should return expected AAAA record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) Expect(err).To(BeNil()) }) }) - Describe("Allocate next available PTR Record ", func() { + Describe("Negative case: returns an error message when an IPv4 address is passed", func() { cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" netviewName := "private" - cidr := "53.0.0.0/24" + cidr := "10.0.0./24" ipAddr := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) vmID := "93f9249abc039284" vmName := "dummyvm" dnsView := "default" - recordName := "test" - fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) - - aniFakeConnector := &fakeConnector{ - createObjectObj: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - }), - getObjectRef: fakeRefReturn, - getObjectObj: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - Ref: fakeRefReturn, - }), - getObjectQueryParams: NewQueryParams(false, nil), - resultObject: NewRecordPTR(RecordPTR{ - PtrdName: recordName, - View: dnsView, - Ipv4Addr: ipAddr, - Ref: fakeRefReturn, - }), - fakeRefReturn: fakeRefReturn, + recordName := "test.domain.com" + comment := "Test creation" + ea := EA{"VM Name": vmName, "VM ID": vmID} + conn := &fakeConnector{ + createObjectObj: NewRecordAAAA( + dnsView, recordName, ipAddr, false, 0, comment, ea, ""), + createObjectError: fmt.Errorf("cannot parse CIDR value: invalid CIDR address: 10.0.0./24"), } - objMgr := NewObjectManager(aniFakeConnector, cmpType, tenantID) + objMgr := NewObjectManager(conn, cmpType, tenantID) - ea := make(EA) - aniFakeConnector.createObjectObj.(*RecordPTR).Ea = ea - aniFakeConnector.createObjectObj.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.createObjectObj.(*RecordPTR).Ea["VM Name"] = vmName + var actualRecord, expectedObj *RecordAAAA + var err error + It("should pass expected AAAA record Object to CreateObject", func() { + actualRecord, err = objMgr.CreateAAAARecord(netviewName, dnsView, recordName, cidr, "", false, uint32(0), comment, ea) + }) + It("should return expected AAAA record Object", func() { + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.createObjectError)) + }) + }) - aniFakeConnector.resultObject.(*RecordPTR).Ea = ea - aniFakeConnector.resultObject.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.resultObject.(*RecordPTR).Ea["VM Name"] = vmName + Describe("Get AAAA record", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + dnsView := "default" + recordName := "test.domain.com" + ipAddr := "2001:db8:abcd:14::1" + fakeRefReturn := fmt.Sprintf("record:aaaa/ZG5zLmJpbmRfY25h:%s/default", recordName) - aniFakeConnector.getObjectObj.(*RecordPTR).Ea = ea - aniFakeConnector.getObjectObj.(*RecordPTR).Ea["VM ID"] = vmID - aniFakeConnector.getObjectObj.(*RecordPTR).Ea["VM Name"] = vmName + queryParams := NewQueryParams( + false, + map[string]string{ + "view": dnsView, + "name": recordName, + "ipv6addr": ipAddr, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordAAAA(), + getObjectQueryParams: queryParams, + resultObject: []RecordAAAA{*NewRecordAAAA(dnsView, recordName, ipAddr, false, 0, "", nil, fakeRefReturn)}, + fakeRefReturn: fakeRefReturn, + } - var actualRecord *RecordPTR + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.resultObject.([]RecordAAAA)[0].Ipv6Addr = ipAddr + var actualRecord *RecordAAAA var err error - It("should pass expected PTR record Object to CreateObject", func() { - actualRecord, err = objMgr.CreatePTRRecord(netviewName, dnsView, recordName, cidr, ipAddr, ea) + It("should pass expected AAAA record Object to GetObject", func() { + actualRecord, err = objMgr.GetAAAARecord(dnsView, recordName, ipAddr) }) - It("should return expected PTR record Object", func() { - Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) + + It("should return expected AAAA record Object", func() { + Expect(*actualRecord).To(Equal(conn.resultObject.([]RecordAAAA)[0])) Expect(err).To(BeNil()) }) }) - Describe("Allocate CNAME Record ", func() { + Describe("Negative case: returns an error when all the required fields are not passed", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + recordName := "test.domain.com" + ipAddr := "2001:db8:abcd:14::1" + fakeRefReturn := fmt.Sprintf("record:aaaa/ZG5zLmJpbmRfY25h:%s/default", recordName) + + queryParams := NewQueryParams( + false, + map[string]string{ + "name": recordName, + "ipv6addr": ipAddr, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordAAAA(), + getObjectQueryParams: queryParams, + fakeRefReturn: fakeRefReturn, + getObjectError: fmt.Errorf("DNS view, IPv6 address and record name of the record are required to retreive a unique AAAA record"), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord, expectedObj *RecordAAAA + var err error + It("should pass expected AAAA record Object to GetObject", func() { + actualRecord, err = objMgr.GetAAAARecord("", recordName, ipAddr) + }) + + It("should return expected AAAA record Object", func() { + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.getObjectError)) + }) + }) + + Describe("Update AAAA-record, literal value", func() { + var ( + err error + objMgr IBObjectManager + conn *fakeConnector + ) + cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" - canonical := "test-canonical" dnsView := "default" + recordName := "test.domain.com" + refBase := "ZG5zLm5ldHdvcmtfdmlldyQyMw" + initIpAddr := "2001:db8:abcd:12::1" + initUseTtl := true + newRecordName := "test1.domain.com" + newIpAddr := "2001:db8:abcd:12::2" + newTtl := uint32(0) + newUseTtl := false + + It("Negative case: updating an AAAA-record which does not exist", func() { + initRef := fmt.Sprintf( + "record:aaaa/%s:%s/%s", + refBase, recordName, dnsView) + getObjIn := NewEmptyRecordAAAA() + + conn = &fakeConnector{ + getObjectObj: getObjIn, + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: initRef, + getObjectError: fmt.Errorf("test error"), + resultObject: NewEmptyRecordAAAA(), + fakeRefReturn: "", + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + _, err = objMgr.UpdateAAAARecord(initRef, "", newRecordName, "", newIpAddr, newUseTtl, newTtl, "some comment", nil) + Expect(err).ToNot(BeNil()) + }) + + It("Negative case: updating an AAAA-record with no update access", func() { + initRef := fmt.Sprintf( + "record:aaaa/%s:%s/%s", + refBase, recordName, dnsView) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initComment := "initial comment" + initObj := NewRecordAAAA(dnsView, recordName, initIpAddr, initUseTtl, newTtl, initComment, initialEas, initRef) + + getObjIn := NewEmptyRecordAAAA() + + newEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + + newComment := "test comment 1" + updateObjIn := NewRecordAAAA("", newRecordName, newIpAddr, newUseTtl, newTtl, newComment, newEas, initRef) + + conn = &fakeConnector{ + getObjectObj: getObjIn, + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: initRef, + getObjectError: nil, + resultObject: initObj, + + updateObjectObj: updateObjIn, + updateObjectRef: initRef, + updateObjectError: fmt.Errorf("test error"), + fakeRefReturn: "", + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + _, err = objMgr.UpdateAAAARecord(initRef, "", newRecordName, newIpAddr, "", newUseTtl, newTtl, newComment, newEas) + Expect(err).ToNot(BeNil()) + }) + }) + + Describe("Allocate specific PTR Record with IPv6 Address", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + ipAddr := "2001:db8:abcd:14::1" vmID := "93f9249abc039284" vmName := "dummyvm" - recordName := "test" - fakeRefReturn := fmt.Sprintf("record:cname/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + dnsView := "default" + ptrdname := "test" + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.1.0.0.d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa/default") - aniFakeConnector := &fakeConnector{ - createObjectObj: NewRecordCNAME(RecordCNAME{ - Name: recordName, - View: dnsView, - Canonical: canonical, - }), - getObjectRef: fakeRefReturn, - getObjectObj: NewRecordCNAME(RecordCNAME{ - Name: recordName, - View: dnsView, - Canonical: canonical, - Ref: fakeRefReturn, - }), + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordPTR(), getObjectQueryParams: NewQueryParams(false, nil), - resultObject: NewRecordCNAME(RecordCNAME{ - Name: recordName, - View: dnsView, - Canonical: canonical, - Ref: fakeRefReturn, - }), - fakeRefReturn: fakeRefReturn, + resultObject: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + fakeRefReturn: fakeRefReturn, } - objMgr := NewObjectManager(aniFakeConnector, cmpType, tenantID) - ea := make(EA) - aniFakeConnector.createObjectObj.(*RecordCNAME).Ea = ea - aniFakeConnector.createObjectObj.(*RecordCNAME).Ea["VM ID"] = vmID - aniFakeConnector.createObjectObj.(*RecordCNAME).Ea["VM Name"] = vmName - - aniFakeConnector.resultObject.(*RecordCNAME).Ea = ea - aniFakeConnector.resultObject.(*RecordCNAME).Ea["VM ID"] = vmID - aniFakeConnector.resultObject.(*RecordCNAME).Ea["VM Name"] = vmName + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Ipv6Addr = ipAddr - aniFakeConnector.getObjectObj.(*RecordCNAME).Ea = ea - aniFakeConnector.getObjectObj.(*RecordCNAME).Ea["VM ID"] = vmID - aniFakeConnector.getObjectObj.(*RecordCNAME).Ea["VM Name"] = vmName - var actualRecord *RecordCNAME + var actualRecord *RecordPTR var err error - It("should pass expected CNAME record Object to CreateObject", func() { - actualRecord, err = objMgr.CreateCNAMERecord(canonical, recordName, dnsView, ea) + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, ptrdname, "", "", ipAddr, useTtl, 0, comment, eas) }) - It("should return expected CNAME record Object", func() { - Expect(actualRecord).To(Equal(aniFakeConnector.resultObject)) + It("should return expected PTR record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) Expect(err).To(BeNil()) }) }) + Describe("Allocate specific PTR Record with IPv4 Address", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + ipAddr := "10.0.0.1" + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + ptrdname := "test" + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:2.0.0.10.in-addr.arpa/default") + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Ipv4Addr = ipAddr + + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, ptrdname, "", "", ipAddr, useTtl, 0, comment, eas) + }) + It("should return expected PTR record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) + + Describe("Allocate next available PTR Record-IPv4", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + netviewName := "private" + cidr := "10.0.0.0/24" + ipAddr := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + ptrdname := "test" + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:2.0.0.10.in-addr.arpa/default") + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Ipv4Addr = ipAddr + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord(netviewName, dnsView, ptrdname, "", cidr, "", useTtl, 0, comment, eas) + }) + It("should return expected PTR record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) + + Describe("Allocate next available PTR Record-IPv6", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + netviewName := "private" + cidr := "2001:db8:abcd:14::/64" + ipAddr := fmt.Sprintf("func:nextavailableip:%s,%s", cidr, netviewName) + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + ptrdname := "test" + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.1.0.0.d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa/default") + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Ipv6Addr = ipAddr + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord(netviewName, dnsView, ptrdname, "", cidr, "", useTtl, 0, comment, eas) + }) + It("should return expected PTR record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) + + Describe("Allocate a PTR Record in forward mapping zone", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + recordName := "test-ptr-record.test.com" + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + ptrdname := "test" + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:%s/%s", recordName, dnsView) + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, comment, eas), + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Name = recordName + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, ptrdname, recordName, "", "", useTtl, 0, comment, eas) + }) + It("should return expected PTR record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) + + Describe("Negative case: returns an error message if ptrdname is not entered", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + recordName := "test-ptr-record.test.com" + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, "", useTtlPtr, 0, comment, eas), + createObjectError: fmt.Errorf("ptrdname is a required field to create a PTR record"), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Name = recordName + var actualRecord, expectedObj *RecordPTR + var err error + expectedObj = nil + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, "", recordName, "", "", useTtl, 0, comment, eas) + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Not(BeNil())) + }) + }) + + Describe("Negative case: returns an error message if an invalid IP address is passed", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + ipAddr := "10.0.0.300" + ptrdname := "ptr-test.infoblox.com" + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + comment := "creation test" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, "", useTtlPtr, 0, comment, eas), + createObjectError: fmt.Errorf("%s is an invalid IP address", ipAddr), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.createObjectObj.(*RecordPTR).Ipv4Addr = ipAddr + var actualRecord, expectedObj *RecordPTR + var err error + expectedObj = nil + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, ptrdname, "", "", ipAddr, useTtl, 0, comment, eas) + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.createObjectError)) + }) + }) + + Describe("Negative case: returns an error message if the required fields for creation of record is empty", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + vmID := "93f9249abc039284" + vmName := "dummyvm" + dnsView := "default" + comment := "creation test" + ptrdname := "ptr-test.infoblox.com" + eas := EA{"VM Name": vmName, "VM ID": vmID} + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + + conn := &fakeConnector{ + createObjectObj: NewRecordPTR(dnsView, "", useTtlPtr, 0, comment, eas), + createObjectError: fmt.Errorf("CIDR and network view are required to allocate a next available IP address\n" + + "IP address is required to create PTR record in reverse mapping zone\n" + + "record name is required to create a record in forwarrd mapping zone"), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord, expectedObj *RecordPTR + var err error + expectedObj = nil + It("should pass expected PTR record Object to CreateObject", func() { + actualRecord, err = objMgr.CreatePTRRecord("", dnsView, ptrdname, "", "", "", useTtl, 0, comment, eas) + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.createObjectError)) + }) + }) + + Describe("Get PTR record-IPv4", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + dnsView := "default" + ptrdname := "test" + ipAddr := "10.0.0.1" + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:1.0.0.10.in-addr.arpa/default") + + queryParams := NewQueryParams( + false, + map[string]string{ + "view": dnsView, + "ptrdname": ptrdname, + "ipv4addr": ipAddr, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: queryParams, + resultObject: []RecordPTR{*NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, "", nil)}, + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + conn.resultObject.([]RecordPTR)[0].Ipv4Addr = ipAddr + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to GetObject", func() { + actualRecord, err = objMgr.GetPTRRecord(dnsView, ptrdname, "", ipAddr) + }) + + It("should return expected PTR record Object", func() { + Expect(*actualRecord).To(Equal(conn.resultObject.([]RecordPTR)[0])) + Expect(err).To(BeNil()) + }) + }) + + Describe("Get PTR record-IPv6", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + dnsView := "default" + ptrdname := "test" + ipAddr := "2001:db8:abcd:14::1" + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.1.0.0.d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa/default") + + queryParams := NewQueryParams( + false, + map[string]string{ + "view": dnsView, + "ptrdname": ptrdname, + "ipv6addr": ipAddr, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: queryParams, + resultObject: []RecordPTR{*NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, "", nil)}, + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to GetObject", func() { + actualRecord, err = objMgr.GetPTRRecord(dnsView, ptrdname, "", ipAddr) + }) + + It("should return expected PTR record Object", func() { + Expect(*actualRecord).To(Equal(conn.resultObject.([]RecordPTR)[0])) + Expect(err).To(BeNil()) + }) + }) + + Describe("Get PTR record-name(forward mapping zone)", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + dnsView := "default" + ptrdname := "test" + recordName := "test-ptr-record.test.com" + useTtl := false + useTtlPtr := new(bool) + *useTtlPtr = useTtl + fakeRefReturn := fmt.Sprintf("record:ptr/ZG5zLmJpbmRfY25h:%s/%s", recordName, dnsView) + + queryParams := NewQueryParams( + false, + map[string]string{ + "view": dnsView, + "ptrdname": ptrdname, + "name": recordName, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: queryParams, + resultObject: []RecordPTR{*NewRecordPTR(dnsView, ptrdname, useTtlPtr, 0, "", nil)}, + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + + var actualRecord *RecordPTR + var err error + It("should pass expected PTR record Object to GetObject", func() { + actualRecord, err = objMgr.GetPTRRecord(dnsView, ptrdname, recordName, "") + }) + + It("should return expected PTR record Object", func() { + Expect(*actualRecord).To(Equal(conn.resultObject.([]RecordPTR)[0])) + Expect(err).To(BeNil()) + }) + }) + + Describe("Update PTR record", func() { + var ( + err error + objMgr IBObjectManager + conn *fakeConnector + ref string + actualObj *RecordPTR + ) + + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + refBase := "ZG5zLm5ldHdvcmtfdmlldyQyMw" + ptrdname := "test" + ipv4Addr := "10.0.0.1" + ipv6Addr := "2001:db8:abcd:14::1" + recordName := "test-ptr-record.test.com" + useTtl := false + ttl := uint32(0) + + It("IPv4, updating ptrdname, IPv4 address, comment and EAs", func() { + ref = fmt.Sprintf("record:ptr/%s:1.0.0.10.in-addr.arpa/default", refBase) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initObj := NewRecordPTR("", ptrdname, &useTtl, ttl, "old comment", initialEas) + initObj.Ref = ref + initObj.Ipv4Addr = ipv4Addr + + setEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + expectedEas := setEas + + comment := "test comment 1" + updateUseTtl := true + updateTtl := uint32(10) + newPtrdname := "test-update-ptr.test.com" + updateIpAddr := "10.0.0.2" + updatedRef := fmt.Sprintf("record:ptr/%s:2.0.0.10.in-addr.arpa/default", refBase) + updateObjIn := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + updateObjIn.Ref = ref + updateObjIn.Ipv4Addr = updateIpAddr + + expectedObj := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + expectedObj.Ref = updatedRef + expectedObj.Ipv4Addr = updateIpAddr + + conn = &fakeConnector{ + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: updatedRef, + getObjectError: nil, + resultObject: expectedObj, + + updateObjectObj: updateObjIn, + updateObjectRef: ref, + updateObjectError: nil, + + fakeRefReturn: updatedRef, + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + actualObj, err = objMgr.UpdatePTRRecord(ref, newPtrdname, "", updateIpAddr, updateUseTtl, updateTtl, comment, setEas) + Expect(err).To(BeNil()) + Expect(*actualObj).To(BeEquivalentTo(*expectedObj)) + }) + + It("IPv6: updating ptrdname, TTl fields, IPv6 address, comment and EAs", func() { + ref = fmt.Sprintf("record:ptr/%s:1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.1.0.0.d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa/default", refBase) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initObj := NewRecordPTR("", ptrdname, &useTtl, ttl, "old comment", initialEas) + initObj.Ref = ref + initObj.Ipv4Addr = ipv6Addr + + setEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + expectedEas := setEas + + comment := "test comment 1" + updateUseTtl := true + updateTtl := uint32(10) + newPtrdname := "test-update" + updateIpAddr := "2001:db8:abcd:14::2" + updatedRef := fmt.Sprintf("record:ptr/%s:2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.1.0.0.d.c.b.a.8.b.d.0.1.0.0.2.ip6.arpa/default", refBase) + updateObjIn := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + updateObjIn.Ref = ref + updateObjIn.Ipv6Addr = updateIpAddr + + expectedObj := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + expectedObj.Ref = updatedRef + expectedObj.Ipv6Addr = updateIpAddr + + conn = &fakeConnector{ + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: updatedRef, + getObjectError: nil, + resultObject: expectedObj, + + updateObjectObj: updateObjIn, + updateObjectRef: ref, + updateObjectError: nil, + + fakeRefReturn: updatedRef, + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + actualObj, err = objMgr.UpdatePTRRecord(ref, newPtrdname, "", updateIpAddr, updateUseTtl, updateTtl, comment, setEas) + Expect(err).To(BeNil()) + Expect(*actualObj).To(BeEquivalentTo(*expectedObj)) + }) + + It("Updating ptrdname, TTl fields, record name, comment and EAs", func() { + ref = fmt.Sprintf("record:ptr/%s:%s/default", refBase, recordName) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initObj := NewRecordPTR("", ptrdname, &useTtl, ttl, "old comment", initialEas) + initObj.Ref = ref + initObj.Name = recordName + + setEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + expectedEas := setEas + + comment := "test comment 1" + updateUseTtl := true + updateTtl := uint32(10) + newPtrdname := "test-update" + updateName := "test-ptr-update" + updatedRef := fmt.Sprintf("record:ptr/%s:%s/20", refBase, newPtrdname) + updateObjIn := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + updateObjIn.Ref = ref + updateObjIn.Name = updateName + + expectedObj := NewRecordPTR("", newPtrdname, &updateUseTtl, updateTtl, comment, expectedEas) + expectedObj.Ref = updatedRef + expectedObj.Name = updateName + + conn = &fakeConnector{ + getObjectObj: NewEmptyRecordPTR(), + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: updatedRef, + getObjectError: nil, + resultObject: expectedObj, + + updateObjectObj: updateObjIn, + updateObjectRef: ref, + updateObjectError: nil, + + fakeRefReturn: updatedRef, + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + actualObj, err = objMgr.UpdatePTRRecord(ref, newPtrdname, updateName, "", updateUseTtl, updateTtl, comment, setEas) + Expect(err).To(BeNil()) + Expect(*actualObj).To(BeEquivalentTo(*expectedObj)) + }) + }) + + Describe("Allocate CNAME Record ", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + canonical := "test-canonical.domain.com" + dnsView := "default" + vmID := "93f9249abc039284" + vmName := "dummyvm" + recordName := "test.domain.com" + useTtl := false + ttl := uint32(0) + comment := "test CNAME record creation" + fakeRefReturn := fmt.Sprintf("record:cname/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + eas := EA{"VM Name": vmName, "VM ID": vmID} + + conn := &fakeConnector{ + createObjectObj: NewRecordCNAME(dnsView, canonical, recordName, useTtl, ttl, comment, eas, ""), + getObjectRef: fakeRefReturn, + getObjectObj: NewEmptyRecordCNAME(), + getObjectQueryParams: NewQueryParams(false, nil), + resultObject: NewRecordCNAME(dnsView, canonical, recordName, useTtl, ttl, comment, eas, fakeRefReturn), + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord *RecordCNAME + var err error + It("should pass expected CNAME record Object to CreateObject", func() { + actualRecord, err = objMgr.CreateCNAMERecord(dnsView, canonical, recordName, useTtl, ttl, comment, eas) + }) + It("should return expected CNAME record Object", func() { + Expect(actualRecord).To(Equal(conn.resultObject)) + Expect(err).To(BeNil()) + }) + }) + + Describe("Negative case: returns an error message if required fields are not passed", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + dnsView := "default" + vmID := "93f9249abc039284" + vmName := "dummyvm" + useTtl := false + ttl := uint32(0) + comment := "test CNAME record creation" + eas := EA{"VM Name": vmName, "VM ID": vmID} + + conn := &fakeConnector{ + createObjectObj: NewRecordCNAME(dnsView, "", "", useTtl, ttl, comment, eas, ""), + createObjectError: fmt.Errorf("canonical name and record name fields are required to create a CNAME record"), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord, expectedObj *RecordCNAME + var err error + It("should pass expected CNAME record Object to CreateObject", func() { + actualRecord, err = objMgr.CreateCNAMERecord(dnsView, "", "", useTtl, ttl, comment, eas) + }) + It("should return expected CNAME record Object", func() { + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.createObjectError)) + }) + }) + + Describe("Get CNAME Record ", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + canonical := "test-canonical.domain.com" + dnsView := "default" + recordName := "test.domain.com" + useTtl := false + ttl := uint32(0) + fakeRefReturn := fmt.Sprintf("record:cname/ZG5zLmJpbmRfY25h:%s/%20%20", recordName) + + queryParams := NewQueryParams( + false, + map[string]string{ + "view": dnsView, + "canonical": canonical, + "name": recordName, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordCNAME(), + getObjectQueryParams: queryParams, + resultObject: []RecordCNAME{*NewRecordCNAME(dnsView, canonical, recordName, useTtl, ttl, "", nil, fakeRefReturn)}, + fakeRefReturn: fakeRefReturn, + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord *RecordCNAME + var err error + It("should pass expected CNAME record Object to CreateObject", func() { + actualRecord, err = objMgr.GetCNAMERecord(dnsView, canonical, recordName) + }) + It("should return expected CNAME record Object", func() { + Expect(*actualRecord).To(Equal(conn.resultObject.([]RecordCNAME)[0])) + Expect(err).To(BeNil()) + }) + }) + + Describe("Negative case: return an error mesage when the required fields to get a unique record are not passed", func() { + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + canonical := "test-canonical.domain.com" + recordName := "test.domain.com" + + queryParams := NewQueryParams( + false, + map[string]string{ + "canonical": canonical, + "name": recordName, + }) + conn := &fakeConnector{ + getObjectRef: "", + getObjectObj: NewEmptyRecordCNAME(), + getObjectQueryParams: queryParams, + getObjectError: fmt.Errorf("DNS view, canonical name and record name of the record are required to retreive a unique CNAME record"), + } + + objMgr := NewObjectManager(conn, cmpType, tenantID) + var actualRecord, expectedObj *RecordCNAME + var err error + expectedObj = nil + It("should pass expected CNAME record Object to CreateObject", func() { + actualRecord, err = objMgr.GetCNAMERecord("", canonical, recordName) + }) + It("should return expected CNAME record Object", func() { + Expect(actualRecord).To(Equal(expectedObj)) + Expect(err).To(Equal(conn.getObjectError)) + }) + }) + + Describe("Update PTR record", func() { + var ( + err error + objMgr IBObjectManager + conn *fakeConnector + ref string + actualObj *RecordCNAME + ) + + cmpType := "Docker" + tenantID := "01234567890abcdef01234567890abcdef" + refBase := "ZG5zLm5ldHdvcmtfdmlldyQyMw" + canonical := "test-canonical.domain.com" + recordName := "test.domain.com" + useTtl := false + ttl := uint32(0) + + It("IPv4, updating ptrdname, IPv4 address, comment and EAs", func() { + ref = fmt.Sprintf("record:cname/%s:%s", refBase, recordName) + initialEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_old_value", + "ea3": "ea3_value", + "ea4": "ea4_value", + "ea5": "ea5_old_value"} + initObj := NewRecordCNAME("", canonical, recordName, useTtl, ttl, "old comment", initialEas, ref) + initObj.Ref = ref + + setEas := EA{ + "ea0": "ea0_old_value", + "ea1": "ea1_new_value", + "ea2": "ea2_new_value", + "ea5": "ea5_old_value"} + expectedEas := setEas + + comment := "test comment 1" + updateUseTtl := true + updateTtl := uint32(10) + newCanonical := "test-canonical-update.domain.com" + newRecordName := "test-update.domain.com" + updatedRef := fmt.Sprintf("record:cname/%s:%s", refBase, newRecordName) + updateObjIn := NewRecordCNAME("", newCanonical, newRecordName, updateUseTtl, updateTtl, comment, expectedEas, ref) + + expectedObj := NewRecordCNAME("", newCanonical, newRecordName, updateUseTtl, updateTtl, comment, expectedEas, updatedRef) + + conn = &fakeConnector{ + getObjectObj: NewEmptyRecordCNAME(), + getObjectQueryParams: NewQueryParams(false, nil), + getObjectRef: updatedRef, + getObjectError: nil, + resultObject: expectedObj, + + updateObjectObj: updateObjIn, + updateObjectRef: ref, + updateObjectError: nil, + + fakeRefReturn: updatedRef, + } + objMgr = NewObjectManager(conn, cmpType, tenantID) + + actualObj, err = objMgr.UpdateCNAMERecord(ref, newCanonical, newRecordName, updateUseTtl, updateTtl, comment, setEas) + Expect(err).To(BeNil()) + Expect(*actualObj).To(BeEquivalentTo(*expectedObj)) + }) + }) + Describe("Allocate TXT Record ", func() { cmpType := "Docker" tenantID := "01234567890abcdef01234567890abcdef" diff --git a/objects.go b/objects.go index 9e343b8d..75fe2f6f 100644 --- a/objects.go +++ b/objects.go @@ -429,13 +429,17 @@ type RecordA struct { Name string `json:"name,omitempty"` View string `json:"view,omitempty"` Zone string `json:"zone,omitempty"` + TTL uint32 `json:"ttl"` + UseTTL bool `json:"use_ttl"` + Comment string `json:"comment"` Ea EA `json:"extattrs"` } func NewEmptyRecordA() *RecordA { res := &RecordA{} res.objectType = "record:a" - res.returnFields = []string{"extattrs", "ipv4addr", "name", "view", "zone"} + res.returnFields = []string{ + "extattrs", "ipv4addr", "name", "view", "zone", "comment", "ttl", "use_ttl"} return res } @@ -445,6 +449,9 @@ func NewRecordA( zone string, name string, ipAddr string, + ttl uint32, + useTTL bool, + comment string, eas EA, ref string) *RecordA { @@ -453,6 +460,53 @@ func NewRecordA( res.Zone = zone res.Name = name res.Ipv4Addr = ipAddr + res.TTL = ttl + res.UseTTL = useTTL + res.Comment = comment + res.Ea = eas + res.Ref = ref + + return res +} + +type RecordAAAA struct { + IBBase `json:"-"` + Ref string `json:"_ref,omitempty"` + Ipv6Addr string `json:"ipv6addr,omitempty"` + Name string `json:"name,omitempty"` + View string `json:"view,omitempty"` + Zone string `json:"zone,omitempty"` + UseTtl bool `json:"use_ttl"` + Ttl uint32 `json:"ttl"` + Comment string `json:"comment"` + Ea EA `json:"extattrs"` +} + +func NewEmptyRecordAAAA() *RecordAAAA { + res := &RecordAAAA{} + res.objectType = "record:aaaa" + res.returnFields = []string{"extattrs", "ipv6addr", "name", "view", "zone", "use_ttl", "ttl", "comment"} + + return res +} + +func NewRecordAAAA( + view string, + name string, + ipAddr string, + useTtl bool, + ttl uint32, + comment string, + eas EA, + ref string) *RecordAAAA { + + res := NewEmptyRecordAAAA() + res.View = view + res.Name = name + res.Ipv6Addr = ipAddr + res.UseTtl = useTtl + res.Ttl = ttl + res.Comment = comment res.Ea = eas res.Ref = ref @@ -463,21 +517,37 @@ type RecordPTR struct { IBBase `json:"-"` Ref string `json:"_ref,omitempty"` Ipv4Addr string `json:"ipv4addr,omitempty"` + Ipv6Addr string `json:"ipv6addr,omitempty"` Name string `json:"name,omitempty"` PtrdName string `json:"ptrdname,omitempty"` View string `json:"view,omitempty"` Zone string `json:"zone,omitempty"` Ea EA `json:"extattrs"` + UseTtl *bool `json:"use_ttl,omitempty"` + Ttl uint32 `json:"ttl,omitempty"` + Comment string `json:"comment,omitempty"` } -func NewRecordPTR(rptr RecordPTR) *RecordPTR { - res := rptr +func NewEmptyRecordPTR() *RecordPTR { + res := RecordPTR{} res.objectType = "record:ptr" - res.returnFields = []string{"extattrs", "ipv4addr", "ptrdname", "view", "zone"} + res.returnFields = []string{"extattrs", "ipv4addr", "ipv6addr", "ptrdname", "view", "zone", "comment", "use_ttl", "ttl"} return &res } +func NewRecordPTR(dnsView string, ptrdname string, useTtl *bool, ttl uint32, comment string, ea EA) *RecordPTR { + res := NewEmptyRecordPTR() + res.View = dnsView + res.PtrdName = ptrdname + res.UseTtl = useTtl + res.Ttl = ttl + res.Comment = comment + res.Ea = ea + + return res +} + type RecordCNAME struct { IBBase `json:"-"` Ref string `json:"_ref,omitempty"` @@ -486,14 +556,39 @@ type RecordCNAME struct { View string `json:"view,omitempty"` Zone string `json:"zone,omitempty"` Ea EA `json:"extattrs"` + Comment string `json:"comment"` + UseTtl bool `json:"use_ttl"` + Ttl uint32 `json:"ttl"` } -func NewRecordCNAME(rc RecordCNAME) *RecordCNAME { - res := rc +func NewEmptyRecordCNAME() *RecordCNAME { + res := &RecordCNAME{} res.objectType = "record:cname" - res.returnFields = []string{"extattrs", "canonical", "name", "view", "zone"} + res.returnFields = []string{"extattrs", "canonical", "name", "view", "zone", "comment", "ttl", "use_ttl"} - return &res + return res +} + +func NewRecordCNAME(dnsView string, + canonical string, + recordName string, + useTtl bool, + ttl uint32, + comment string, + ea EA, + ref string) *RecordCNAME { + + res := NewEmptyRecordCNAME() + res.View = dnsView + res.Canonical = canonical + res.Name = recordName + res.UseTtl = useTtl + res.Ttl = ttl + res.Comment = comment + res.Ea = ea + res.Ref = ref + + return res } type HostRecordIpv4Addr struct { @@ -679,6 +774,10 @@ func NewZoneDelegated(za ZoneDelegated) *ZoneDelegated { return &res } +func (ea EA) Count() int { + return len(ea) +} + func (ea EA) MarshalJSON() ([]byte, error) { m := make(map[string]interface{}) for k, v := range ea { diff --git a/objects_test.go b/objects_test.go index 0a79157e..78827d6d 100644 --- a/objects_test.go +++ b/objects_test.go @@ -2,7 +2,6 @@ package ibclient import ( "encoding/json" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -377,69 +376,118 @@ var _ = Describe("Objects", func() { name := "bind_a.domain.com" view := "default" zone := "domain.com" + ttl := uint32(500) + useTTL := true + comment := "testcomment" + eas := EA{ + "TestEA1": "testea1 value", + "Location": "east coast", + } - ra := NewRecordA(view, zone, name, ipv4addr, nil, "") + ra := NewRecordA(view, zone, name, ipv4addr, ttl, useTTL, comment, eas, "") It("should set fields correctly", func() { Expect(ra.Ipv4Addr).To(Equal(ipv4addr)) Expect(ra.Name).To(Equal(name)) Expect(ra.View).To(Equal(view)) Expect(ra.Zone).To(Equal(zone)) + + Expect(ra.TTL).To(Equal(ttl)) + Expect(ra.UseTTL).To(Equal(useTTL)) + Expect(ra.Comment).To(Equal(comment)) + Expect(ra.Ea).To(Equal(eas)) }) It("should set base fields correctly", func() { Expect(ra.ObjectType()).To(Equal("record:a")) - Expect(ra.ReturnFields()).To(ConsistOf("extattrs", "ipv4addr", "name", "view", "zone")) + Expect(ra.ReturnFields()).To(ConsistOf( + "extattrs", "ipv4addr", "name", "view", "zone", "comment", "ttl", "use_ttl")) + }) + }) + + Context("RecordAAAA object", func() { + ipv6addr := "2001:db8:abcd:14::1" + name := "bind_a.domain.com" + view := "default" + useTtl := true + ttl := uint32(10) + comment := "test comment" + ea := EA{"VM Name": "test-vm"} + + ra := NewRecordAAAA(view, name, ipv6addr, useTtl, ttl, comment, ea, "") + + It("should set fields correctly", func() { + Expect(ra.Ipv6Addr).To(Equal(ipv6addr)) + Expect(ra.Name).To(Equal(name)) + Expect(ra.View).To(Equal(view)) + Expect(ra.UseTtl).To(Equal(useTtl)) + Expect(ra.Ttl).To(Equal(ttl)) + Expect(ra.Comment).To(Equal(comment)) + Expect(ra.Ea).To(Equal(ea)) + }) + + It("should set base fields correctly", func() { + Expect(ra.ObjectType()).To(Equal("record:aaaa")) + Expect(ra.ReturnFields()).To(ConsistOf("extattrs", "ipv6addr", "name", "view", "zone", "use_ttl", "ttl", "comment")) }) }) Context("RecordPtr object", func() { ipv4addr := "1.1.1.1" + ipv6addr := "2001::/64" ptrdname := "bind_a.domain.com" view := "default" zone := "domain.com" + useTtl := false + comment := "test client" + eas := EA{"VM Name": "test"} - rptr := NewRecordPTR(RecordPTR{ - Ipv4Addr: ipv4addr, - PtrdName: ptrdname, - View: view, - Zone: zone}) + rptr := NewRecordPTR(view, ptrdname, &useTtl, 0, comment, eas) + rptr.Zone = zone + rptr.Ipv4Addr = ipv4addr + rptr.Ipv6Addr = ipv6addr It("should set fields correctly", func() { Expect(rptr.Ipv4Addr).To(Equal(ipv4addr)) + Expect(rptr.Ipv6Addr).To(Equal(ipv6addr)) Expect(rptr.PtrdName).To(Equal(ptrdname)) Expect(rptr.View).To(Equal(view)) Expect(rptr.Zone).To(Equal(zone)) + Expect(rptr.UseTtl).To(Equal(&useTtl)) + Expect(rptr.Comment).To(Equal(comment)) + Expect(rptr.Ea).To(Equal(eas)) }) It("should set base fields correctly", func() { Expect(rptr.ObjectType()).To(Equal("record:ptr")) - Expect(rptr.ReturnFields()).To(ConsistOf("extattrs", "ipv4addr", "ptrdname", "view", "zone")) + Expect(rptr.ReturnFields()).To(ConsistOf("extattrs", "ipv4addr", "ipv6addr", "ptrdname", "view", "zone", "comment", "use_ttl", "ttl")) }) }) Context("RecordCNAME object", func() { canonical := "cname.domain.com" name := "bind_cname.domain.com" + useTtl := false + ttl := uint32(0) view := "default" - zone := "domain.com" + comment := "test CNAME" + eas := EA{"VM Name": "test"} - rc := NewRecordCNAME(RecordCNAME{ - Canonical: canonical, - Name: name, - View: view, - Zone: zone}) + rc := NewRecordCNAME(view, canonical, name, useTtl, ttl, comment, eas, "") It("should set fields correctly", func() { Expect(rc.Canonical).To(Equal(canonical)) Expect(rc.Name).To(Equal(name)) + Expect(rc.UseTtl).To(Equal(useTtl)) + Expect(rc.Ttl).To(Equal(ttl)) Expect(rc.View).To(Equal(view)) - Expect(rc.Zone).To(Equal(zone)) + Expect(rc.Comment).To(Equal(comment)) + Expect(rc.Ea).To(Equal(eas)) }) It("should set base fields correctly", func() { Expect(rc.ObjectType()).To(Equal("record:cname")) - Expect(rc.ReturnFields()).To(ConsistOf("extattrs", "canonical", "name", "view", "zone")) + Expect(rc.ReturnFields()).To(ConsistOf("extattrs", "canonical", "name", "view", "zone", "comment", "ttl", "use_ttl")) }) })