vmware_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // +build amd64
  2. // Copyright 2015 CoreOS, Inc.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package vmware
  16. import (
  17. "errors"
  18. "fmt"
  19. "io/ioutil"
  20. "net"
  21. "os"
  22. "reflect"
  23. "testing"
  24. "github.com/rancher/os/config/cloudinit/datasource"
  25. "github.com/rancher/os/netconf"
  26. )
  27. type MockHypervisor map[string]string
  28. func (h MockHypervisor) ReadConfig(key string) (string, error) {
  29. fmt.Printf("read(%s) %s\n", key, h[key])
  30. return h[key], nil
  31. }
  32. var fakeDownloader urlDownloadFunction = func(url string) ([]byte, error) {
  33. mapping := map[string]struct {
  34. data []byte
  35. err error
  36. }{
  37. "http://good.example.com": {[]byte("test config"), nil},
  38. "http://bad.example.com": {nil, errors.New("Not found")},
  39. }
  40. val := mapping[url]
  41. return val.data, val.err
  42. }
  43. func TestFetchMetadata(t *testing.T) {
  44. tests := []struct {
  45. variables MockHypervisor
  46. metadata datasource.Metadata
  47. err error
  48. }{
  49. {
  50. variables: map[string]string{
  51. "hostname": "first",
  52. "interface.0.mac": "test mac",
  53. "interface.0.dhcp": "yes",
  54. },
  55. metadata: datasource.Metadata{
  56. Hostname: "first",
  57. NetworkConfig: netconf.NetworkConfig{
  58. Interfaces: map[string]netconf.InterfaceConfig{
  59. "eth0": netconf.InterfaceConfig{
  60. Match: "mac:test mac",
  61. DHCP: true,
  62. Addresses: []string{},
  63. },
  64. },
  65. },
  66. // NetworkConfig: map[string]string{
  67. // "interface.0.mac": "test mac",
  68. // "interface.0.dhcp": "yes",
  69. // },
  70. },
  71. },
  72. {
  73. variables: map[string]string{
  74. "hostname": "second",
  75. "interface.0.name": "test name",
  76. "interface.0.dhcp": "yes",
  77. },
  78. metadata: datasource.Metadata{
  79. Hostname: "second",
  80. NetworkConfig: netconf.NetworkConfig{
  81. Interfaces: map[string]netconf.InterfaceConfig{
  82. "eth0": netconf.InterfaceConfig{
  83. Match: "test name",
  84. DHCP: true,
  85. Addresses: []string{},
  86. },
  87. },
  88. },
  89. // NetworkConfig: map[string]string{
  90. // "interface.0.name": "test name",
  91. // "interface.0.dhcp": "yes",
  92. // },
  93. },
  94. },
  95. {
  96. variables: map[string]string{
  97. "hostname": "test host",
  98. "interface.0.mac": "test mac",
  99. "interface.0.role": "private",
  100. "interface.0.ip.0.address": "fe00::100/64",
  101. "interface.0.route.0.gateway": "fe00::1",
  102. "interface.0.route.0.destination": "::",
  103. },
  104. metadata: datasource.Metadata{
  105. Hostname: "test host",
  106. PrivateIPv6: net.ParseIP("fe00::100"),
  107. NetworkConfig: netconf.NetworkConfig{
  108. Interfaces: map[string]netconf.InterfaceConfig{
  109. "eth0": netconf.InterfaceConfig{
  110. Match: "mac:test mac",
  111. DHCP: false,
  112. Addresses: []string{
  113. "fe00::100/64",
  114. },
  115. Gateway: "fe00::1",
  116. //TODO: Destination
  117. },
  118. },
  119. },
  120. // NetworkConfig: map[string]string{
  121. // "interface.0.mac": "test mac",
  122. // "interface.0.ip.0.address": "fe00::100/64",
  123. // "interface.0.route.0.gateway": "fe00::1",
  124. // "interface.0.route.0.destination": "::",
  125. // },
  126. },
  127. },
  128. {
  129. variables: map[string]string{
  130. "hostname": "test host",
  131. "interface.0.name": "test name",
  132. "interface.0.role": "public",
  133. "interface.0.ip.0.address": "10.0.0.100/24",
  134. "interface.0.ip.1.address": "10.0.0.101/24",
  135. "interface.0.route.0.gateway": "10.0.0.1",
  136. "interface.0.route.0.destination": "0.0.0.0",
  137. "interface.1.mac": "test mac",
  138. "interface.1.role": "private",
  139. "interface.1.route.0.gateway": "10.0.0.2",
  140. "interface.1.route.0.destination": "0.0.0.0",
  141. "interface.1.ip.0.address": "10.0.0.102/24",
  142. },
  143. metadata: datasource.Metadata{
  144. Hostname: "test host",
  145. PublicIPv4: net.ParseIP("10.0.0.101"),
  146. PrivateIPv4: net.ParseIP("10.0.0.102"),
  147. NetworkConfig: netconf.NetworkConfig{
  148. Interfaces: map[string]netconf.InterfaceConfig{
  149. "eth0": netconf.InterfaceConfig{
  150. Match: "test name",
  151. DHCP: false,
  152. Addresses: []string{
  153. "10.0.0.100/24",
  154. "10.0.0.101/24",
  155. },
  156. Gateway: "10.0.0.1",
  157. //TODO: Destination
  158. },
  159. "eth1": netconf.InterfaceConfig{
  160. Match: "mac:test mac",
  161. DHCP: false,
  162. Addresses: []string{
  163. "10.0.0.102/24",
  164. },
  165. Gateway: "10.0.0.2",
  166. //TODO: Destination
  167. },
  168. },
  169. },
  170. // NetworkConfig: map[string]string{
  171. // "interface.0.name": "test name",
  172. // "interface.0.ip.0.address": "10.0.0.100/24",
  173. // "interface.0.ip.1.address": "10.0.0.101/24",
  174. // "interface.0.route.0.gateway": "10.0.0.1",
  175. // "interface.0.route.0.destination": "0.0.0.0",
  176. // "interface.1.mac": "test mac",
  177. // "interface.1.route.0.gateway": "10.0.0.2",
  178. // "interface.1.route.0.destination": "0.0.0.0",
  179. // "interface.1.ip.0.address": "10.0.0.102/24",
  180. // },
  181. },
  182. },
  183. }
  184. for i, tt := range tests {
  185. v := VMWare{readConfig: tt.variables.ReadConfig}
  186. metadata, err := v.FetchMetadata()
  187. if !reflect.DeepEqual(tt.err, err) {
  188. t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
  189. }
  190. if !reflect.DeepEqual(tt.metadata, metadata) {
  191. t.Errorf("bad metadata (#%d): want %#v, got %#v", i, tt.metadata, metadata)
  192. }
  193. }
  194. }
  195. func TestFetchUserdata(t *testing.T) {
  196. tests := []struct {
  197. variables MockHypervisor
  198. userdata string
  199. err error
  200. }{
  201. {},
  202. {
  203. variables: map[string]string{"cloud-init.config.data": "test config"},
  204. userdata: "test config",
  205. },
  206. {
  207. variables: map[string]string{
  208. "cloud-init.data.encoding": "",
  209. "cloud-init.config.data": "test config",
  210. },
  211. userdata: "test config",
  212. },
  213. {
  214. variables: map[string]string{
  215. "cloud-init.data.encoding": "base64",
  216. "cloud-init.config.data": "dGVzdCBjb25maWc=",
  217. },
  218. userdata: "test config",
  219. },
  220. {
  221. variables: map[string]string{
  222. "cloud-init.data.encoding": "gzip+base64",
  223. "cloud-init.config.data": "H4sIABaoWlUAAytJLS5RSM7PS8tMBwCQiHNZCwAAAA==",
  224. },
  225. userdata: "test config",
  226. },
  227. {
  228. variables: map[string]string{
  229. "cloud-init.data.encoding": "test encoding",
  230. },
  231. err: errors.New(`Unsupported encoding "test encoding"`),
  232. },
  233. {
  234. variables: map[string]string{
  235. "cloud-init.config.url": "http://good.example.com",
  236. },
  237. userdata: "test config",
  238. },
  239. {
  240. variables: map[string]string{
  241. "cloud-init.config.url": "http://bad.example.com",
  242. },
  243. err: errors.New("Not found"),
  244. },
  245. }
  246. for i, tt := range tests {
  247. v := VMWare{
  248. readConfig: tt.variables.ReadConfig,
  249. urlDownload: fakeDownloader,
  250. }
  251. userdata, err := v.FetchUserdata()
  252. if !reflect.DeepEqual(tt.err, err) {
  253. t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
  254. }
  255. if tt.userdata != string(userdata) {
  256. t.Errorf("bad userdata (#%d): want %q, got %q", i, tt.userdata, userdata)
  257. }
  258. }
  259. }
  260. func TestFetchUserdataError(t *testing.T) {
  261. testErr := errors.New("test error")
  262. _, err := VMWare{readConfig: func(_ string) (string, error) { return "", testErr }}.FetchUserdata()
  263. if testErr != err {
  264. t.Errorf("bad error: want %v, got %v", testErr, err)
  265. }
  266. }
  267. func TestOvfTransport(t *testing.T) {
  268. tests := []struct {
  269. document string
  270. metadata datasource.Metadata
  271. userdata []byte
  272. }{
  273. {
  274. document: `<?xml version="1.0" encoding="UTF-8"?>
  275. <Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"
  276. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  277. xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
  278. oe:id="CoreOS-vmw">
  279. <PlatformSection>
  280. <Kind>VMware ESXi</Kind>
  281. <Version>5.5.0</Version>
  282. <Vendor>VMware, Inc.</Vendor>
  283. <Locale>en</Locale>
  284. </PlatformSection>
  285. <PropertySection>
  286. <Property oe:key="foo" oe:value="42"/>
  287. <Property oe:key="guestinfo.cloud-init.config.url" oe:value="http://good.example.com"/>
  288. <Property oe:key="guestinfo.hostname" oe:value="test host"/>
  289. <Property oe:key="guestinfo.interface.0.name" oe:value="test name"/>
  290. <Property oe:key="guestinfo.interface.0.role" oe:value="public"/>
  291. <Property oe:key="guestinfo.interface.0.ip.0.address" oe:value="10.0.0.100/24"/>
  292. <Property oe:key="guestinfo.interface.0.ip.1.address" oe:value="10.0.0.101/24"/>
  293. <Property oe:key="guestinfo.interface.0.route.0.gateway" oe:value="10.0.0.1"/>
  294. <Property oe:key="guestinfo.interface.0.route.0.destination" oe:value="0.0.0.0"/>
  295. <Property oe:key="guestinfo.interface.1.mac" oe:value="test mac"/>
  296. <Property oe:key="guestinfo.interface.1.role" oe:value="private"/>
  297. <Property oe:key="guestinfo.interface.1.route.0.gateway" oe:value="10.0.0.2"/>
  298. <Property oe:key="guestinfo.interface.1.route.0.destination" oe:value="0.0.0.0"/>
  299. <Property oe:key="guestinfo.interface.1.ip.0.address" oe:value="10.0.0.102/24"/>
  300. </PropertySection>
  301. </Environment>`,
  302. metadata: datasource.Metadata{
  303. Hostname: "test host",
  304. PublicIPv4: net.ParseIP("10.0.0.101"),
  305. PrivateIPv4: net.ParseIP("10.0.0.102"),
  306. NetworkConfig: netconf.NetworkConfig{
  307. Interfaces: map[string]netconf.InterfaceConfig{
  308. "eth0": netconf.InterfaceConfig{
  309. Match: "test name",
  310. DHCP: false,
  311. Addresses: []string{
  312. "10.0.0.100/24",
  313. "10.0.0.101/24",
  314. },
  315. Gateway: "10.0.0.1",
  316. //TODO: Destination
  317. },
  318. "eth1": netconf.InterfaceConfig{
  319. Match: "mac:test mac",
  320. DHCP: false,
  321. Addresses: []string{
  322. "10.0.0.102/24",
  323. },
  324. Gateway: "10.0.0.2",
  325. //TODO: Destination
  326. },
  327. },
  328. },
  329. },
  330. userdata: []byte("test config"),
  331. },
  332. }
  333. for i, tt := range tests {
  334. file, err := ioutil.TempFile(os.TempDir(), "ovf")
  335. if err != nil {
  336. t.Errorf("error creating ovf file (#%d)", i)
  337. }
  338. defer os.Remove(file.Name())
  339. file.WriteString(tt.document)
  340. v := NewDatasource(file.Name())
  341. if v == nil {
  342. continue
  343. }
  344. v.urlDownload = fakeDownloader
  345. metadata, err := v.FetchMetadata()
  346. userdata, err := v.FetchUserdata()
  347. if !reflect.DeepEqual(tt.metadata, metadata) {
  348. t.Errorf("bad metadata (#%d): want %#v, got %#v", i, tt.metadata, metadata)
  349. }
  350. if !reflect.DeepEqual(tt.userdata, userdata) {
  351. t.Errorf("bad userdata (#%d): want %#v, got %#v", i, tt.userdata, userdata)
  352. }
  353. }
  354. }