waagent.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2015 CoreOS, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package waagent
  15. import (
  16. "encoding/xml"
  17. "fmt"
  18. "io/ioutil"
  19. "net"
  20. "os"
  21. "path"
  22. "github.com/rancher/os/log"
  23. "github.com/rancher/os/config/cloudinit/datasource"
  24. )
  25. type Waagent struct {
  26. root string
  27. readFile func(filename string) ([]byte, error)
  28. lastError error
  29. }
  30. func NewDatasource(root string) *Waagent {
  31. return &Waagent{root, ioutil.ReadFile, nil}
  32. }
  33. func (a *Waagent) IsAvailable() bool {
  34. _, a.lastError = os.Stat(path.Join(a.root, "provisioned"))
  35. return !os.IsNotExist(a.lastError)
  36. }
  37. func (a *Waagent) Finish() error {
  38. return nil
  39. }
  40. func (a *Waagent) String() string {
  41. return fmt.Sprintf("%s: %s (lastError: %s)", a.Type(), a.root, a.lastError)
  42. }
  43. func (a *Waagent) AvailabilityChanges() bool {
  44. return true
  45. }
  46. func (a *Waagent) ConfigRoot() string {
  47. return a.root
  48. }
  49. func (a *Waagent) FetchMetadata() (metadata datasource.Metadata, err error) {
  50. var metadataBytes []byte
  51. if metadataBytes, err = a.tryReadFile(path.Join(a.root, "SharedConfig.xml")); err != nil {
  52. return
  53. }
  54. if len(metadataBytes) == 0 {
  55. return
  56. }
  57. type Instance struct {
  58. ID string `xml:"id,attr"`
  59. Address string `xml:"address,attr"`
  60. InputEndpoints struct {
  61. Endpoints []struct {
  62. LoadBalancedPublicAddress string `xml:"loadBalancedPublicAddress,attr"`
  63. } `xml:"Endpoint"`
  64. }
  65. }
  66. type SharedConfig struct {
  67. Incarnation struct {
  68. Instance string `xml:"instance,attr"`
  69. }
  70. Instances struct {
  71. Instances []Instance `xml:"Instance"`
  72. }
  73. }
  74. var m SharedConfig
  75. if err = xml.Unmarshal(metadataBytes, &m); err != nil {
  76. return
  77. }
  78. var instance Instance
  79. for _, i := range m.Instances.Instances {
  80. if i.ID == m.Incarnation.Instance {
  81. instance = i
  82. break
  83. }
  84. }
  85. metadata.PrivateIPv4 = net.ParseIP(instance.Address)
  86. for _, e := range instance.InputEndpoints.Endpoints {
  87. host, _, err := net.SplitHostPort(e.LoadBalancedPublicAddress)
  88. if err == nil {
  89. metadata.PublicIPv4 = net.ParseIP(host)
  90. break
  91. }
  92. }
  93. return
  94. }
  95. func (a *Waagent) FetchUserdata() ([]byte, error) {
  96. return a.tryReadFile(path.Join(a.root, "CustomData"))
  97. }
  98. func (a *Waagent) Type() string {
  99. return "Waagent"
  100. }
  101. func (a *Waagent) tryReadFile(filename string) ([]byte, error) {
  102. log.Printf("Attempting to read from %q\n", filename)
  103. data, err := a.readFile(filename)
  104. if os.IsNotExist(err) {
  105. err = nil
  106. }
  107. return data, err
  108. }