~cloud-green/juju-core/charmstore-sdist

« back to all changes in this revision

Viewing changes to launchpad.net/juju-core/provider/azure/environprovider.go

  • Committer: Casey Marshall
  • Date: 2014-03-27 15:59:46 UTC
  • Revision ID: cmars@cmarstech.com-20140327155946-8huorf37g0zwar43
Source distribution of launchpad.net/juju-core created 20140327105939

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package azure
 
5
 
 
6
import (
 
7
        "encoding/xml"
 
8
        "fmt"
 
9
        "io/ioutil"
 
10
 
 
11
        "github.com/juju/loggo"
 
12
 
 
13
        "launchpad.net/juju-core/environs"
 
14
        "launchpad.net/juju-core/environs/config"
 
15
)
 
16
 
 
17
// Register the Azure provider with Juju.
 
18
func init() {
 
19
        environs.RegisterProvider("azure", azureEnvironProvider{})
 
20
}
 
21
 
 
22
// Logger for the Azure provider.
 
23
var logger = loggo.GetLogger("juju.provider.azure")
 
24
 
 
25
type azureEnvironProvider struct{}
 
26
 
 
27
// azureEnvironProvider implements EnvironProvider.
 
28
var _ environs.EnvironProvider = (*azureEnvironProvider)(nil)
 
29
 
 
30
// Open is specified in the EnvironProvider interface.
 
31
func (prov azureEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) {
 
32
        logger.Debugf("opening environment %q.", cfg.Name())
 
33
        // We can't return NewEnviron(cfg) directly here because otherwise,
 
34
        // when err is not nil, we end up with a non-nil returned environ and
 
35
        // this breaks the loop in cmd/jujud/upgrade.go:run() (see
 
36
        // http://golang.org/doc/faq#nil_error for the gory details).
 
37
        environ, err := NewEnviron(cfg)
 
38
        if err != nil {
 
39
                return nil, err
 
40
        }
 
41
        return environ, nil
 
42
}
 
43
 
 
44
// Prepare is specified in the EnvironProvider interface.
 
45
func (prov azureEnvironProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
 
46
        // TODO prepare environment as necessary
 
47
        return prov.Open(cfg)
 
48
}
 
49
 
 
50
// PublicAddress is specified in the EnvironProvider interface.
 
51
func (prov azureEnvironProvider) PublicAddress() (string, error) {
 
52
        config, err := parseWALAConfig()
 
53
        if err != nil {
 
54
                logger.Errorf("error parsing Windows Azure Linux Agent config file (%q): %v", _WALAConfigPath, err)
 
55
                return "", err
 
56
        }
 
57
        return config.getDeploymentFQDN(), nil
 
58
}
 
59
 
 
60
// PrivateAddress is specified in the EnvironProvider interface.
 
61
func (prov azureEnvironProvider) PrivateAddress() (string, error) {
 
62
        config, err := parseWALAConfig()
 
63
        if err != nil {
 
64
                logger.Errorf("error parsing Windows Azure Linux Agent config file (%q): %v", _WALAConfigPath, err)
 
65
                return "", err
 
66
        }
 
67
        return config.getInternalIP(), nil
 
68
}
 
69
 
 
70
// The XML Windows Azure Linux Agent (WALA) is the agent which runs on all
 
71
// the Linux Azure VMs.  The hostname of the VM is the service name and the
 
72
// juju instanceId is (by design), the deployment's name.
 
73
//
 
74
// See https://github.com/windows-azure/walinuxagent for more details.
 
75
//
 
76
// Here is an example content of such a config file:
 
77
// <?xml version="1.0" encoding="utf-8"?>
 
78
// <SharedConfig version="1.0.0.0" goalStateIncarnation="1">
 
79
//   <Deployment name="b6de4c4c7d4a49c39270e0c57481fd9b" guid="{495985a8-8e5a-49aa-826f-d1f7f51045b6}" incarnation="0">
 
80
//    <Service name="gwaclmachineex95rsek" guid="{00000000-0000-0000-0000-000000000000}" />
 
81
//    <ServiceInstance name="b6de4c4c7d4a49c39270e0c57481fd9b.0" guid="{9806cac7-e566-42b8-9ecb-de8da8f69893}" />
 
82
//  [...]
 
83
//  <Instances>
 
84
//    <Instance id="gwaclroleldc1o5p" address="10.76.200.59">
 
85
//      [...]
 
86
//    </Instance>
 
87
//  </Instances>
 
88
//  </Deployment>
 
89
// </SharedConfig>
 
90
 
 
91
// Structures used to parse the XML Windows Azure Linux Agent (WALA)
 
92
// configuration file.
 
93
 
 
94
type WALASharedConfig struct {
 
95
        XMLName    xml.Name       `xml:"SharedConfig"`
 
96
        Deployment WALADeployment `xml:"Deployment"`
 
97
        Instances  []WALAInstance `xml:"Instances>Instance"`
 
98
}
 
99
 
 
100
// getDeploymentName returns the deployment name referenced by the
 
101
// configuration.
 
102
// Confusingly, this is stored in the 'name' attribute of the 'Service'
 
103
// element.
 
104
func (config *WALASharedConfig) getDeploymentName() string {
 
105
        return config.Deployment.Service.Name
 
106
}
 
107
 
 
108
// getDeploymentFQDN returns the FQDN of this deployment.
 
109
// The hostname is taken from the 'name' attribute of the Service element
 
110
// embedded in the Deployment element.  The domain name is Azure's fixed
 
111
// domain name: 'cloudapp.net'.
 
112
func (config *WALASharedConfig) getDeploymentFQDN() string {
 
113
        return fmt.Sprintf("%s.%s", config.getDeploymentName(), AZURE_DOMAIN_NAME)
 
114
}
 
115
 
 
116
// getInternalIP returns the internal IP for this deployment.
 
117
// The internalIP is the internal IP of the only instance in this deployment.
 
118
func (config *WALASharedConfig) getInternalIP() string {
 
119
        return config.Instances[0].Address
 
120
}
 
121
 
 
122
type WALADeployment struct {
 
123
        Name    string                `xml:"name,attr"`
 
124
        Service WALADeploymentService `xml:"Service"`
 
125
}
 
126
 
 
127
type WALADeploymentService struct {
 
128
        Name string `xml:"name,attr"`
 
129
}
 
130
 
 
131
type WALAInstance struct {
 
132
        Address string `xml:"address,attr"`
 
133
}
 
134
 
 
135
// Path to the WALA configuration file.
 
136
var _WALAConfigPath = "/var/lib/waagent/SharedConfig.xml"
 
137
 
 
138
func parseWALAConfig() (*WALASharedConfig, error) {
 
139
        data, err := ioutil.ReadFile(_WALAConfigPath)
 
140
        if err != nil {
 
141
                return nil, err
 
142
        }
 
143
        config := &WALASharedConfig{}
 
144
        err = xml.Unmarshal(data, config)
 
145
        if err != nil {
 
146
                return nil, err
 
147
        }
 
148
        return config, nil
 
149
}