terraform/vendor/github.com/moul/anonuuid/anonuuid.go

230 lines
5.1 KiB
Go
Raw Normal View History

Add scaleway provider (#7331) * Add scaleway provider this PR allows the entire scaleway stack to be managed with terraform example usage looks like this: ``` provider "scaleway" { api_key = "snap" organization = "snip" } resource "scaleway_ip" "base" { server = "${scaleway_server.base.id}" } resource "scaleway_server" "base" { name = "test" # ubuntu 14.04 image = "aecaed73-51a5-4439-a127-6d8229847145" type = "C2S" } resource "scaleway_volume" "test" { name = "test" size_in_gb = 20 type = "l_ssd" } resource "scaleway_volume_attachment" "test" { server = "${scaleway_server.base.id}" volume = "${scaleway_volume.test.id}" } resource "scaleway_security_group" "base" { name = "public" description = "public gateway" } resource "scaleway_security_group_rule" "http-ingress" { security_group = "${scaleway_security_group.base.id}" action = "accept" direction = "inbound" ip_range = "0.0.0.0/0" protocol = "TCP" port = 80 } resource "scaleway_security_group_rule" "http-egress" { security_group = "${scaleway_security_group.base.id}" action = "accept" direction = "outbound" ip_range = "0.0.0.0/0" protocol = "TCP" port = 80 } ``` Note that volume attachments require the server to be stopped, which can lead to downtimes of you attach new volumes to already used servers * Update IP read to handle 404 gracefully * Read back resource on update * Ensure IP detachment works as expected Sadly this is not part of the official scaleway api just yet * Adjust detachIP helper based on feedback from @QuentinPerez in https://github.com/scaleway/scaleway-cli/pull/378 * Cleanup documentation * Rename api_key to access_key following @stack72 suggestion and rename the provider api_key for more clarity * Make tests less chatty by using custom logger
2016-07-13 22:03:41 +02:00
package anonuuid
import (
"fmt"
"log"
"math/rand"
"regexp"
"strings"
"sync"
"time"
)
var (
// UUIDRegex is the regex used to find UUIDs in texts
UUIDRegex = "[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}"
)
// AnonUUID is the main structure, it contains the cache map and helpers
type AnonUUID struct {
cache map[string]string
guard sync.Mutex // cache guard
// Hexspeak flag will generate hexspeak style fake UUIDs
Hexspeak bool
// Random flag will generate random fake UUIDs
Random bool
// Prefix will be the beginning of all the generated UUIDs
Prefix string
// Suffix will be the end of all the generated UUIDs
Suffix string
// AllowNonUUIDInput tells FakeUUID to accept non UUID input string
AllowNonUUIDInput bool
// KeepBeginning tells FakeUUID to let the beginning of the UUID as it is
KeepBeginning bool
// KeepEnd tells FakeUUID to let the last part of the UUID as it is
KeepEnd bool
}
// Sanitize takes a string as input and return sanitized string
func (a *AnonUUID) Sanitize(input string) string {
r := regexp.MustCompile(UUIDRegex)
return r.ReplaceAllStringFunc(input, func(m string) string {
parts := r.FindStringSubmatch(m)
return a.FakeUUID(parts[0])
})
}
// FakeUUID takes a word (real UUID or standard string) and returns its corresponding (mapped) fakeUUID
func (a *AnonUUID) FakeUUID(input string) string {
if !a.AllowNonUUIDInput {
err := IsUUID(input)
if err != nil {
return "invaliduuid"
}
}
a.guard.Lock()
defer a.guard.Unlock()
if _, ok := a.cache[input]; !ok {
if a.KeepBeginning {
a.Prefix = input[:8]
}
if a.KeepEnd {
a.Suffix = input[36-12:]
}
if a.Prefix != "" {
matched, err := regexp.MatchString("^[a-z0-9]+$", a.Prefix)
if err != nil || !matched {
a.Prefix = "invalidprefix"
}
}
if a.Suffix != "" {
matched, err := regexp.MatchString("^[a-z0-9]+$", a.Suffix)
if err != nil || !matched {
a.Suffix = "invalsuffix"
}
}
var fakeUUID string
var err error
if a.Hexspeak {
fakeUUID, err = GenerateHexspeakUUID(len(a.cache))
} else if a.Random {
fakeUUID, err = GenerateRandomUUID(10)
} else {
fakeUUID, err = GenerateLenUUID(len(a.cache))
}
if err != nil {
log.Fatalf("Failed to generate an UUID: %v", err)
}
if a.Prefix != "" {
fakeUUID, err = PrefixUUID(a.Prefix, fakeUUID)
if err != nil {
panic(err)
}
}
if a.Suffix != "" {
fakeUUID, err = SuffixUUID(a.Suffix, fakeUUID)
if err != nil {
panic(err)
}
}
// FIXME: check for duplicates and retry
a.cache[input] = fakeUUID
}
return a.cache[input]
}
// New returns a prepared AnonUUID structure
func New() *AnonUUID {
return &AnonUUID{
cache: make(map[string]string),
Hexspeak: false,
Random: false,
}
}
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
// PrefixUUID returns a prefixed UUID
func PrefixUUID(prefix string, uuid string) (string, error) {
uuidLetters := uuid[:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36]
prefixedUUID, err := FormatUUID(prefix + uuidLetters)
if err != nil {
return "", err
}
return prefixedUUID, nil
}
// SuffixUUID returns a suffixed UUID
func SuffixUUID(suffix string, uuid string) (string, error) {
uuidLetters := uuid[:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36]
uuidLetters = uuidLetters[:32-len(suffix)] + suffix
suffixedUUID, err := FormatUUID(uuidLetters)
if err != nil {
return "", err
}
return suffixedUUID, nil
}
// IsUUID returns nil if the input is an UUID, else it returns an error
func IsUUID(input string) error {
matched, err := regexp.MatchString("^"+UUIDRegex+"$", input)
if err != nil {
return err
}
if !matched {
return fmt.Errorf("String '%s' is not a valid UUID", input)
}
return nil
}
// FormatUUID takes a string in input and return an UUID formatted string by repeating the string and placing dashes if necessary
func FormatUUID(part string) (string, error) {
if len(part) < 1 {
return "", fmt.Errorf("Empty UUID")
}
if len(part) < 32 {
part = strings.Repeat(part, 32)
}
if len(part) > 32 {
part = part[:32]
}
uuid := part[:8] + "-" + part[8:12] + "-1" + part[13:16] + "-" + part[16:20] + "-" + part[20:32]
err := IsUUID(uuid)
if err != nil {
return "", err
}
return uuid, nil
}
// GenerateRandomUUID returns an UUID based on random strings
func GenerateRandomUUID(length int) (string, error) {
var letters = []rune("abcdef0123456789")
b := make([]rune, length)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return FormatUUID(string(b))
}
// GenerateHexspeakUUID returns an UUID formatted string containing hexspeak words
func GenerateHexspeakUUID(i int) (string, error) {
if i < 0 {
i = -i
}
hexspeaks := []string{
"0ff1ce",
"31337",
"4b1d",
"badc0de",
"badcafe",
"badf00d",
"deadbabe",
"deadbeef",
"deadc0de",
"deadfeed",
"fee1bad",
}
return FormatUUID(hexspeaks[i%len(hexspeaks)])
}
// GenerateLenUUID returns an UUID formatted string based on an index number
func GenerateLenUUID(i int) (string, error) {
if i < 0 {
i = 2<<29 + i
}
return FormatUUID(fmt.Sprintf("%x", i))
}