fastdns: Do not overwrite existing TXT records (#774)

This commit is contained in:
Ludovic Fernandez 2019-02-04 22:12:03 +01:00 committed by GitHub
parent 0e6e4807b1
commit c4730a6ec3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 186 additions and 160 deletions

12
Gopkg.lock generated
View file

@ -55,7 +55,7 @@
revision = "a3fa4a771d87bda2514a90a157e1fed1b6897d2e" revision = "a3fa4a771d87bda2514a90a157e1fed1b6897d2e"
[[projects]] [[projects]]
digest = "1:d677d9bb0dfb2cf2ec6ab5ff1d2deb08ef88f4b255c9f201f01100933ef001a2" digest = "1:47071ecf8d840dd357ede1b2aed46576bdd0a866adecef3c9e85a00db9672202"
name = "github.com/akamai/AkamaiOPEN-edgegrid-golang" name = "github.com/akamai/AkamaiOPEN-edgegrid-golang"
packages = [ packages = [
"client-v1", "client-v1",
@ -64,8 +64,8 @@
"jsonhooks-v1", "jsonhooks-v1",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "196fbdab2db66d0e231cc363efb63454f55fed1c" revision = "1471ce9c14c6d8c007516e129262962a628fecdf"
version = "v0.6.2" version = "v0.7.3"
[[projects]] [[projects]]
digest = "1:823e87ae25170339e2bfd1d6f7c2e27554c6bb5655f91c67b37bd5be45bb6b32" digest = "1:823e87ae25170339e2bfd1d6f7c2e27554c6bb5655f91c67b37bd5be45bb6b32"
@ -232,12 +232,12 @@
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a" revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]] [[projects]]
digest = "1:a1578f7323eca2b88021fdc9a79a99833d40b12c32a5ea4f284e2fad19ea2657" digest = "1:1bb197a3b5db4e06e00b7560f8e89836c486627f2a0338332ed37daa003d259e"
name = "github.com/google/uuid" name = "github.com/google/uuid"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" revision = "064e2069ce9c359c118179501254f67d7d37ba24"
version = "v1.0.0" version = "0.2"
[[projects]] [[projects]]
branch = "master" branch = "master"

View file

@ -96,3 +96,7 @@
[[constraint]] [[constraint]]
version = "v1.1.0" version = "v1.1.0"
name = "github.com/miekg/dns" name = "github.com/miekg/dns"
[[constraint]]
version = "v0.7.3"
name = "github.com/akamai/AkamaiOPEN-edgegrid-golang"

View file

@ -89,16 +89,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
_ = record.SetField("target", value) _ = record.SetField("target", value)
_ = record.SetField("active", true) _ = record.SetField("active", true)
existingRecord := d.findExistingRecord(zone, recordName) for _, r := range zone.Zone.Txt {
if r != nil && reflect.DeepEqual(r.ToMap(), record.ToMap()) {
if existingRecord != nil {
if reflect.DeepEqual(existingRecord.ToMap(), record.ToMap()) {
return nil return nil
} }
err = zone.RemoveRecord(existingRecord)
if err != nil {
return fmt.Errorf("fastdns: %v", err)
}
} }
return d.createRecord(zone, record) return d.createRecord(zone, record)
@ -119,13 +113,17 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("fastdns: %v", err) return fmt.Errorf("fastdns: %v", err)
} }
existingRecord := d.findExistingRecord(zone, recordName) var removed bool
for _, r := range zone.Zone.Txt {
if existingRecord != nil { if r != nil && r.Name == recordName {
err := zone.RemoveRecord(existingRecord) if zone.RemoveRecord(r) != nil {
if err != nil { return fmt.Errorf("fastdns: %v", err)
return fmt.Errorf("fastdns: %v", err) }
removed = true
} }
}
if removed {
return zone.Save() return zone.Save()
} }
@ -150,16 +148,6 @@ func (d *DNSProvider) findZoneAndRecordName(fqdn, domain string) (string, string
return zone, name, nil return zone, name, nil
} }
func (d *DNSProvider) findExistingRecord(zone *configdns.Zone, recordName string) *configdns.TxtRecord {
for _, r := range zone.Zone.Txt {
if r.Name == recordName {
return r
}
}
return nil
}
func (d *DNSProvider) createRecord(zone *configdns.Zone, record *configdns.TxtRecord) error { func (d *DNSProvider) createRecord(zone *configdns.Zone, record *configdns.TxtRecord) error {
err := zone.AddRecord(record) err := zone.AddRecord(record)
if err != nil { if err != nil {

View file

@ -6,8 +6,11 @@ import (
"errors" "errors"
"io" "io"
"io/ioutil" "io/ioutil"
"mime/multipart"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path/filepath"
"runtime" "runtime"
"strings" "strings"
@ -61,13 +64,21 @@ func NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*h
// NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body // NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body
// The JSON body is encoded and the Content-Type/Accept headers are set automatically. // The JSON body is encoded and the Content-Type/Accept headers are set automatically.
func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) { func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) {
jsonBody, err := jsonhooks.Marshal(body) var req *http.Request
if err != nil { var err error
return nil, err
if body != nil {
jsonBody, err := jsonhooks.Marshal(body)
if err != nil {
return nil, err
}
buf := bytes.NewReader(jsonBody)
req, err = NewRequest(config, method, path, buf)
} else {
req, err = NewRequest(config, method, path, nil)
} }
buf := bytes.NewReader(jsonBody)
req, err := NewRequest(config, method, path, buf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -78,6 +89,36 @@ func NewJSONRequest(config edgegrid.Config, method, path string, body interface{
return req, nil return req, nil
} }
// NewMultiPartFormDataRequest creates an HTTP request that uploads a file to the Akamai API
func NewMultiPartFormDataRequest(config edgegrid.Config, uriPath, filePath string, otherFormParams map[string]string) (*http.Request, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// TODO: make this field name configurable
part, err := writer.CreateFormFile("importFile", filepath.Base(filePath))
if err != nil {
return nil, err
}
_, err = io.Copy(part, file)
for key, val := range otherFormParams {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return nil, err
}
req, err := NewRequest(config, "POST", uriPath, body)
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, err
}
// Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid // Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid
// Authorization header. An edgegrid.Response or an error is returned. // Authorization header. An edgegrid.Response or an error is returned.
func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) { func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {

View file

@ -12,22 +12,42 @@ import (
// APIError exposes an Akamai OPEN Edgegrid Error // APIError exposes an Akamai OPEN Edgegrid Error
type APIError struct { type APIError struct {
error error
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Status int `json:"status"` Status int `json:"status"`
Detail string `json:"detail"` Detail string `json:"detail"`
Instance string `json:"instance"` Errors []APIErrorDetail `json:"errors"`
Method string `json:"method"` Problems []APIErrorDetail `json:"problems"`
ServerIP string `json:"serverIp"` Instance string `json:"instance"`
ClientIP string `json:"clientIp"` Method string `json:"method"`
RequestID string `json:"requestId"` ServerIP string `json:"serverIp"`
RequestTime string `json:"requestTime"` ClientIP string `json:"clientIp"`
Response *http.Response `json:"-"` RequestID string `json:"requestId"`
RawBody string `json:"-"` RequestTime string `json:"requestTime"`
Response *http.Response `json:"-"`
RawBody string `json:"-"`
}
type APIErrorDetail struct {
Type string `json:"type"`
Title string `json:"title"`
Detail string `json:"detail"`
RejectedValue string `json:"rejectedValue"`
} }
func (error APIError) Error() string { func (error APIError) Error() string {
return strings.TrimSpace(fmt.Sprintf("API Error: %d %s %s More Info %s", error.Status, error.Title, error.Detail, error.Type)) var errorDetails string
if len(error.Errors) > 0 {
for _, e := range error.Errors {
errorDetails = fmt.Sprintf("%s \n %s", errorDetails, e)
}
}
if len(error.Problems) > 0 {
for _, e := range error.Problems {
errorDetails = fmt.Sprintf("%s \n %s", errorDetails, e)
}
}
return strings.TrimSpace(fmt.Sprintf("API Error: %d %s %s More Info %s\n %s", error.Status, error.Title, error.Detail, error.Type, errorDetails))
} }
// NewAPIError creates a new API error based on a Response, // NewAPIError creates a new API error based on a Response,
@ -45,7 +65,6 @@ func NewAPIError(response *http.Response) APIError {
// other purposes. // other purposes.
func NewAPIErrorFromBody(response *http.Response, body []byte) APIError { func NewAPIErrorFromBody(response *http.Response, body []byte) APIError {
error := APIError{} error := APIError{}
if err := jsonhooks.Unmarshal(body, &error); err == nil { if err := jsonhooks.Unmarshal(body, &error); err == nil {
error.Status = response.StatusCode error.Status = response.StatusCode
error.Title = response.Status error.Title = response.Status

View file

@ -1323,15 +1323,16 @@ func (record *RrsigRecord) ToMap() map[string]interface{} {
} }
type SoaRecord struct { type SoaRecord struct {
fieldMap []string `json:"-"` fieldMap []string `json:"-"`
TTL int `json:"ttl,omitempty"` originalSerial uint `json:"-"`
Originserver string `json:"originserver,omitempty"` TTL int `json:"ttl,omitempty"`
Contact string `json:"contact,omitempty"` Originserver string `json:"originserver,omitempty"`
Serial uint `json:"serial,omitempty"` Contact string `json:"contact,omitempty"`
Refresh int `json:"refresh,omitempty"` Serial uint `json:"serial,omitempty"`
Retry int `json:"retry,omitempty"` Refresh int `json:"refresh,omitempty"`
Expire int `json:"expire,omitempty"` Retry int `json:"retry,omitempty"`
Minimum uint `json:"minimum,omitempty"` Expire int `json:"expire,omitempty"`
Minimum uint `json:"minimum,omitempty"`
} }
func NewSoaRecord() *SoaRecord { func NewSoaRecord() *SoaRecord {

View file

@ -82,7 +82,7 @@ func GetZone(hostname string) (*Zone, error) {
} else if res.StatusCode == 404 { } else if res.StatusCode == 404 {
return nil, &ZoneError{zoneName: hostname} return nil, &ZoneError{zoneName: hostname}
} else { } else {
err = client.BodyJSON(res, &zone) err = client.BodyJSON(res, zone)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -762,11 +762,18 @@ func (zone *Zone) removeTxtRecord(record *TxtRecord) error {
return errors.New("Txt Record not found") return errors.New("Txt Record not found")
} }
func (zone *Zone) PreMarshalJSON() error { func (zone *Zone) PostUnmarshalJSON() error {
if zone.Zone.Soa.Serial > 0 { if zone.Zone.Soa.Serial > 0 {
zone.Zone.Soa.Serial = zone.Zone.Soa.Serial + 1 zone.Zone.Soa.originalSerial = zone.Zone.Soa.Serial
} else { }
return nil
}
func (zone *Zone) PreMarshalJSON() error {
if zone.Zone.Soa.Serial == 0 {
zone.Zone.Soa.Serial = uint(time.Now().Unix()) zone.Zone.Soa.Serial = uint(time.Now().Unix())
} else if zone.Zone.Soa.Serial == zone.Zone.Soa.originalSerial {
zone.Zone.Soa.Serial = zone.Zone.Soa.Serial + 1
} }
return nil return nil
} }
@ -786,21 +793,24 @@ func (zone *Zone) validateCnames() (bool, []name) {
} }
func (zone *Zone) removeCnameName(host string) { func (zone *Zone) removeCnameName(host string) {
for i, v := range cnameNames { var ncn []name
if v.name == host { for _, v := range cnameNames {
r := cnameNames[:i] if v.name != host {
cnameNames = append(r, cnameNames[i+1:]...) ncn =append(ncn, v)
} }
} }
cnameNames = ncn
} }
func (zone *Zone) removeNonCnameName(host string) { func (zone *Zone) removeNonCnameName(host string) {
for i, v := range nonCnameNames { var ncn []name
if v.name == host { for _, v := range nonCnameNames {
r := nonCnameNames[:i] if v.name != host {
nonCnameNames = append(r, nonCnameNames[i+1:]...) ncn =append(ncn, v)
} }
} }
nonCnameNames = ncn
} }
func (zone *Zone) FindRecords(recordType string, options map[string]interface{}) []DNSRecord { func (zone *Zone) FindRecords(recordType string, options map[string]interface{}) []DNSRecord {

View file

@ -44,7 +44,7 @@ type PreJSONMarshaler interface {
// ImplementsPreJSONMarshaler checks for support for the PreMarshalJSON pre-hook // ImplementsPreJSONMarshaler checks for support for the PreMarshalJSON pre-hook
func ImplementsPreJSONMarshaler(v interface{}) bool { func ImplementsPreJSONMarshaler(v interface{}) bool {
value := reflect.ValueOf(v) value := reflect.ValueOf(v)
if value.Kind() == reflect.Ptr && value.IsNil() { if !value.IsValid() {
return false return false
} }

View file

@ -42,7 +42,7 @@ func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person // NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid. // domain with the id returned by os.Getuid.
// //
// NewDCESecurity(Person, uint32(os.Getuid())) // NewDCEPerson(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) { func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid())) return NewDCESecurity(Person, uint32(os.Getuid()))
} }
@ -50,7 +50,7 @@ func NewDCEPerson() (UUID, error) {
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group // NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid. // domain with the id returned by os.Getgid.
// //
// NewDCESecurity(Group, uint32(os.Getgid())) // NewDCEGroup(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) { func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid())) return NewDCESecurity(Group, uint32(os.Getgid()))
} }

View file

@ -27,7 +27,7 @@ var (
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset() h.Reset()
h.Write(space[:]) h.Write(space[:])
h.Write(data) h.Write([]byte(data))
s := h.Sum(nil) s := h.Sum(nil)
var uuid UUID var uuid UUID
copy(uuid[:], s) copy(uuid[:], s)

View file

@ -15,6 +15,8 @@ func (uuid UUID) MarshalText() ([]byte, error) {
// UnmarshalText implements encoding.TextUnmarshaler. // UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error { func (uuid *UUID) UnmarshalText(data []byte) error {
// See comment in ParseBytes why we do this.
// id, err := ParseBytes(data)
id, err := ParseBytes(data) id, err := ParseBytes(data)
if err == nil { if err == nil {
*uuid = id *uuid = id

View file

@ -5,14 +5,16 @@
package uuid package uuid
import ( import (
"net"
"sync" "sync"
) )
var ( var (
nodeMu sync.Mutex nodeMu sync.Mutex
ifname string // name of interface being used interfaces []net.Interface // cached list of interfaces
nodeID [6]byte // hardware for version 1 UUIDs ifname string // name of interface being used
zeroID [6]byte // nodeID with only 0's nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
) )
// NodeInterface returns the name of the interface from which the NodeID was // NodeInterface returns the name of the interface from which the NodeID was
@ -37,11 +39,20 @@ func SetNodeInterface(name string) bool {
} }
func setNodeInterface(name string) bool { func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js if interfaces == nil {
if iname != "" && addr != nil { var err error
ifname = iname interfaces, err = net.Interfaces()
copy(nodeID[:], addr) if err != nil && name != "" {
return true return false
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
copy(nodeID[:], ifs.HardwareAddr)
ifname = ifs.Name
return true
}
} }
// We found no interfaces with a valid hardware address. If name // We found no interfaces with a valid hardware address. If name
@ -83,6 +94,9 @@ func SetNodeID(id []byte) bool {
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. // not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte { func (uuid UUID) NodeID() []byte {
if len(uuid) != 16 {
return nil
}
var node [6]byte var node [6]byte
copy(node[:], uuid[10:]) copy(node[:], uuid[10:])
return node[:] return node[:]

View file

@ -1,12 +0,0 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This remvoves the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

View file

@ -1,33 +0,0 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

21
vendor/github.com/google/uuid/sql.go generated vendored
View file

@ -13,36 +13,35 @@ import (
// Currently, database types that map to string and []byte are supported. Please // Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types. // consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error { func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) { switch src.(type) {
case nil:
return nil
case string: case string:
// if an empty UUID comes from a table, we return a null UUID // if an empty UUID comes from a table, we return a null UUID
if src == "" { if src.(string) == "" {
return nil return nil
} }
// see Parse for required string format // see Parse for required string format
u, err := Parse(src) u, err := Parse(src.(string))
if err != nil { if err != nil {
return fmt.Errorf("Scan: %v", err) return fmt.Errorf("Scan: %v", err)
} }
*uuid = u *uuid = u
case []byte: case []byte:
b := src.([]byte)
// if an empty UUID comes from a table, we return a null UUID // if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 { if len(b) == 0 {
return nil return nil
} }
// assumes a simple slice of bytes if 16 bytes // assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse // otherwise attempts to parse
if len(src) != 16 { if len(b) != 16 {
return uuid.Scan(string(src)) return uuid.Scan(string(b))
} }
copy((*uuid)[:], src) copy((*uuid)[:], b)
default: default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src) return fmt.Errorf("Scan: unable to scan type %T into UUID", src)

View file

@ -86,7 +86,7 @@ func clockSequence() int {
return int(clockSeq & 0x3fff) return int(clockSeq & 0x3fff)
} }
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to // SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated. // -1 causes a new sequence to be generated.
func SetClockSequence(seq int) { func SetClockSequence(seq int) {
defer timeMu.Unlock() defer timeMu.Unlock()
@ -100,9 +100,9 @@ func setClockSequence(seq int) {
randomBits(b[:]) // clock sequence randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1]) seq = int(b[0])<<8 | int(b[1])
} }
oldSeq := clockSeq old_seq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq { if old_seq != clockSeq {
lasttime = 0 lasttime = 0
} }
} }

View file

@ -58,11 +58,11 @@ func Parse(s string) (UUID, error) {
14, 16, 14, 16,
19, 21, 19, 21,
24, 26, 28, 30, 32, 34} { 24, 26, 28, 30, 32, 34} {
v, ok := xtob(s[x], s[x+1]) if v, ok := xtob(s[x], s[x+1]); !ok {
if !ok {
return uuid, errors.New("invalid UUID format") return uuid, errors.New("invalid UUID format")
} else {
uuid[i] = v
} }
uuid[i] = v
} }
return uuid, nil return uuid, nil
} }
@ -88,22 +88,15 @@ func ParseBytes(b []byte) (UUID, error) {
14, 16, 14, 16,
19, 21, 19, 21,
24, 26, 28, 30, 32, 34} { 24, 26, 28, 30, 32, 34} {
v, ok := xtob(b[x], b[x+1]) if v, ok := xtob(b[x], b[x+1]); !ok {
if !ok {
return uuid, errors.New("invalid UUID format") return uuid, errors.New("invalid UUID format")
} else {
uuid[i] = v
} }
uuid[i] = v
} }
return uuid, nil return uuid, nil
} }
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise. // Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID { func Must(uuid UUID, err error) UUID {
if err != nil { if err != nil {
@ -183,7 +176,7 @@ func (v Variant) String() string {
return fmt.Sprintf("BadVariant%d", int(v)) return fmt.Sprintf("BadVariant%d", int(v))
} }
// SetRand sets the random number generator to r, which implements io.Reader. // SetRand sets the random number generator to r, which implents io.Reader.
// If r.Read returns an error when the package requests random data then // If r.Read returns an error when the package requests random data then
// a panic will be issued. // a panic will be issued.
// //

View file

@ -13,7 +13,7 @@ import (
// or SetNodeInterface then it will be set automatically. If the NodeID cannot // or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by // be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to // SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error. // return the current NewUUID returns Nil and an error.
// //
// In most cases, New should be used. // In most cases, New should be used.
func NewUUID() (UUID, error) { func NewUUID() (UUID, error) {

View file

@ -6,7 +6,7 @@ package uuid
import "io" import "io"
// New creates a new random UUID or panics. New is equivalent to // New is creates a new random UUID or panics. New is equivalent to
// the expression // the expression
// //
// uuid.Must(uuid.NewRandom()) // uuid.Must(uuid.NewRandom())
@ -14,12 +14,12 @@ func New() UUID {
return Must(NewRandom()) return Must(NewRandom())
} }
// NewRandom returns a Random (Version 4) UUID. // NewRandom returns a Random (Version 4) UUID or panics.
// //
// The strength of the UUIDs is based on the strength of the crypto/rand // The strength of the UUIDs is based on the strength of the crypto/rand
// package. // package.
// //
// A note about uniqueness derived from the UUID Wikipedia entry: // A note about uniqueness derived from from the UUID Wikipedia entry:
// //
// Randomly generated UUIDs have 122 random bits. One's annual risk of being // Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that // hit by a meteorite is estimated to be one chance in 17 billion, that