github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/agent/format-1.16.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agent
     5  
     6  import (
     7  	"encoding/base64"
     8  	"fmt"
     9  	"net"
    10  	"strconv"
    11  
    12  	"github.com/juju/names"
    13  	goyaml "gopkg.in/yaml.v1"
    14  
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/version"
    17  )
    18  
    19  var format_1_16 = formatter_1_16{}
    20  
    21  // formatter_1_16 is the formatter for the 1.16 format.
    22  type formatter_1_16 struct {
    23  }
    24  
    25  // Ensure that the formatter_1_16 struct implements the formatter interface.
    26  var _ formatter = formatter_1_16{}
    27  
    28  // format_1_16Serialization holds information for a given agent.
    29  type format_1_16Serialization struct {
    30  	Tag               string
    31  	Nonce             string
    32  	UpgradedToVersion *version.Number `yaml:"upgradedToVersion"`
    33  
    34  	CACert         string
    35  	StateAddresses []string `yaml:",omitempty"`
    36  	StatePassword  string   `yaml:",omitempty"`
    37  
    38  	APIAddresses []string `yaml:",omitempty"`
    39  	APIPassword  string   `yaml:",omitempty"`
    40  
    41  	OldPassword string
    42  	Values      map[string]string
    43  
    44  	// Only state server machines have these next three items
    45  	StateServerCert string `yaml:",omitempty"`
    46  	StateServerKey  string `yaml:",omitempty"`
    47  	APIPort         int    `yaml:",omitempty"`
    48  }
    49  
    50  func init() {
    51  	registerFormat(format_1_16)
    52  }
    53  
    54  const legacyFormatFilename = "format"
    55  
    56  // legacyFormatPrefix is the prefix of the legacy format file.
    57  const legacyFormatPrefix = "format "
    58  
    59  // decode64 makes sure that for an empty string we have a nil slice, not an
    60  // empty slice, which is what the base64 DecodeString function returns.
    61  func decode64(value string) (result []byte, err error) {
    62  	if value != "" {
    63  		result, err = base64.StdEncoding.DecodeString(value)
    64  	}
    65  	return
    66  }
    67  
    68  func (formatter_1_16) version() string {
    69  	return "1.16"
    70  }
    71  
    72  func (formatter_1_16) unmarshal(data []byte) (*configInternal, error) {
    73  	var format format_1_16Serialization
    74  	if err := goyaml.Unmarshal(data, &format); err != nil {
    75  		return nil, err
    76  	}
    77  	caCert, err := decode64(format.CACert)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	stateServerCert, err := decode64(format.StateServerCert)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	stateServerKey, err := decode64(format.StateServerKey)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	if format.UpgradedToVersion == nil {
    90  		// Assume it's 1.16.0.
    91  		upgradedToVersion := version.MustParse("1.16.0")
    92  		format.UpgradedToVersion = &upgradedToVersion
    93  	}
    94  	tag, err := names.ParseTag(format.Tag)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	config := &configInternal{
    99  		tag:               tag,
   100  		nonce:             format.Nonce,
   101  		dataDir:           DefaultDataDir,
   102  		logDir:            DefaultLogDir,
   103  		upgradedToVersion: *format.UpgradedToVersion,
   104  		caCert:            string(caCert),
   105  		oldPassword:       format.OldPassword,
   106  		values:            format.Values,
   107  	}
   108  	if len(format.StateAddresses) > 0 {
   109  		config.stateDetails = &connectionDetails{
   110  			format.StateAddresses,
   111  			format.StatePassword,
   112  		}
   113  	}
   114  
   115  	if len(stateServerKey) != 0 {
   116  		config.servingInfo = &params.StateServingInfo{
   117  			Cert:       string(stateServerCert),
   118  			PrivateKey: string(stateServerKey),
   119  			APIPort:    format.APIPort,
   120  		}
   121  		// There's a private key, then we need the state
   122  		// port, which wasn't directly available in the 1.16 format,
   123  		// but we can infer it from the ports in the state addresses.
   124  		if len(format.StateAddresses) > 0 {
   125  			_, portString, err := net.SplitHostPort(format.StateAddresses[0])
   126  			if err != nil {
   127  				return nil, err
   128  			}
   129  			statePort, err := strconv.Atoi(portString)
   130  			if err != nil {
   131  				return nil, err
   132  			}
   133  			config.servingInfo.StatePort = statePort
   134  		} else {
   135  			return nil, fmt.Errorf("server key found but no state port")
   136  		}
   137  	}
   138  	if len(format.APIAddresses) > 0 {
   139  		config.apiDetails = &connectionDetails{
   140  			format.APIAddresses,
   141  			format.APIPassword,
   142  		}
   143  	}
   144  	return config, nil
   145  }