~arosales/juju-core/update-azure-boilerplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"io"
	"text/template"
)

var configHeader = `## This is the Juju config file, which you can use to specify multiple environments in which to deploy.
## By default Juju ships AWS (default), HP Cloud, OpenStack.
## See https://juju.ubuntu.com/docs for more information

## An environment configuration must always specify at least the following information:
##
## - name (to identify the environment)
## - type (to specify the provider)
## - admin-secret (an arbitrary "password" identifying an client with administrative-level access to system state)

## Values in <brackets> below need to be filled in by the user.

## The default environment is chosen when one is not specified using either:
##   -e, --environment command line parameter
##   JUJU_ENV environment variable
## If both -e and JUJU_ENV are specified, the command line parameter has precedence.
default: amazon

environments:
`

func randomKey() string {
	buf := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, buf)
	if err != nil {
		panic(fmt.Errorf("error from crypto rand: %v", err))
	}
	return fmt.Sprintf("%x", buf)
}

// BoilerplateConfig returns a sample juju configuration.
func BoilerplateConfig() string {
	var config bytes.Buffer

	config.WriteString(configHeader)
	for name, p := range providers {
		t, err := parseTemplate(p.BoilerplateConfig())
		if err != nil {
			panic(fmt.Errorf("cannot parse boilerplate from %s: %v", name, err))
		}
		var ecfg bytes.Buffer
		if err := t.Execute(&ecfg, nil); err != nil {
			panic(fmt.Errorf("cannot generate boilerplate from %s: %v", name, err))
		}
		indent(&config, ecfg.Bytes(), "  ")
	}

	// Sanity check to ensure the boilerplate parses.
	_, err := ReadEnvironsBytes(config.Bytes())
	if err != nil {
		panic(fmt.Errorf("cannot parse %s:\n%v", config.String(), err))
	}
	return config.String()
}

func parseTemplate(s string) (*template.Template, error) {
	t := template.New("")
	t.Funcs(template.FuncMap{"rand": randomKey})
	return t.Parse(s)
}

// indent appends the given text to the given buffer indented by the given indent string.
func indent(b *bytes.Buffer, text []byte, indentStr string) {
	for {
		if len(text) == 0 {
			return
		}
		b.WriteString(indentStr)
		i := bytes.IndexByte(text, '\n')
		if i == -1 {
			b.Write(text)
			b.WriteRune('\n')
			return
		}
		i++
		b.Write(text[0:i])
		text = text[i:]
	}
}