github.com/coreos/mantle@v0.13.0/kola/tests/ignition/resource.go (about)

     1  // Copyright 2017 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  
    15  package ignition
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"net/http"
    22  
    23  	"github.com/coreos/go-semver/semver"
    24  	"github.com/pin/tftp"
    25  
    26  	"github.com/coreos/mantle/kola/cluster"
    27  	"github.com/coreos/mantle/kola/register"
    28  	"github.com/coreos/mantle/platform"
    29  	"github.com/coreos/mantle/platform/conf"
    30  	"github.com/coreos/mantle/platform/machine/packet"
    31  )
    32  
    33  var (
    34  	localClient = conf.Ignition(`{
    35  		  "ignition": {
    36  		      "version": "2.1.0"
    37  		  },
    38  		  "storage": {
    39  		      "files": [
    40  			  {
    41  			      "filesystem": "root",
    42  			      "path": "/var/resource/data",
    43  			      "contents": {
    44  				  "source": "data:,kola-data"
    45  			      },
    46  			      "mode": 420
    47  			  },
    48  			  {
    49  			      "filesystem": "root",
    50  			      "path": "/var/resource/http",
    51  			      "contents": {
    52  				  "source": "http://$IP/http"
    53  			      },
    54  			      "mode": 420
    55  			  },
    56  			  {
    57  			      "filesystem": "root",
    58  			      "path": "/var/resource/tftp",
    59  			      "contents": {
    60  				  "source": "tftp://$IP/tftp"
    61  			      },
    62  			      "mode": 420
    63  			  }
    64  		      ]
    65  		  }
    66  	      }`)
    67  	localClientV3 = conf.Ignition(`{
    68  		  "ignition": {
    69  		      "version": "3.0.0"
    70  		  },
    71  		  "storage": {
    72  		      "files": [
    73  			  {
    74  			      "path": "/var/resource/data",
    75  			      "contents": {
    76  				  "source": "data:,kola-data"
    77  			      },
    78  			      "mode": 420
    79  			  },
    80  			  {
    81  			      "path": "/var/resource/http",
    82  			      "contents": {
    83  				  "source": "http://$IP/http"
    84  			      },
    85  			      "mode": 420
    86  			  },
    87  			  {
    88  			      "path": "/var/resource/tftp",
    89  			      "contents": {
    90  				  "source": "tftp://$IP/tftp"
    91  			      },
    92  			      "mode": 420
    93  			  }
    94  		      ]
    95  		  }
    96  	      }`)
    97  )
    98  
    99  func init() {
   100  	register.Register(&register.Test{
   101  		Name:        "coreos.ignition.resource.local",
   102  		Run:         resourceLocal,
   103  		ClusterSize: 1,
   104  		NativeFuncs: map[string]func() error{
   105  			"Serve": Serve,
   106  		},
   107  		// https://github.com/coreos/bugs/issues/2205
   108  		ExcludePlatforms: []string{"do", "qemu-unpriv"},
   109  		Distros:          []string{"cl", "fcos", "rhcos"},
   110  	})
   111  	register.Register(&register.Test{
   112  		Name:        "coreos.ignition.resource.remote",
   113  		Run:         resourceRemote,
   114  		ClusterSize: 1,
   115  		Flags:       []register.Flag{register.RequiresInternetAccess},
   116  		// https://github.com/coreos/bugs/issues/2205 for DO
   117  		ExcludePlatforms: []string{"do"},
   118  		UserData: conf.Ignition(`{
   119  		  "ignition": {
   120  		      "version": "2.1.0"
   121  		  },
   122  		  "storage": {
   123  		      "files": [
   124  			  {
   125  			      "filesystem": "root",
   126  			      "path": "/var/resource/http",
   127  			      "contents": {
   128  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/anonymous"
   129  			      },
   130  			      "mode": 420
   131  			  },
   132  			  {
   133  			      "filesystem": "root",
   134  			      "path": "/var/resource/https",
   135  			      "contents": {
   136  				  "source": "https://s3-us-west-2.amazonaws.com/kola-fixtures/resources/anonymous"
   137  			      },
   138  			      "mode": 420
   139  			  },
   140  			  {
   141  			      "filesystem": "root",
   142  			      "path": "/var/resource/s3-anon",
   143  			      "contents": {
   144  				  "source": "s3://kola-fixtures/resources/anonymous"
   145  			      },
   146  			      "mode": 420
   147  			  }
   148  		      ]
   149  		  }
   150  	      }`),
   151  		UserDataV3: conf.Ignition(`{
   152  		  "ignition": {
   153  		      "version": "3.0.0"
   154  		  },
   155  		  "storage": {
   156  		      "files": [
   157  			  {
   158  			      "path": "/var/resource/http",
   159  			      "contents": {
   160  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/anonymous"
   161  			      },
   162  			      "mode": 420
   163  			  },
   164  			  {
   165  			      "path": "/var/resource/https",
   166  			      "contents": {
   167  				  "source": "https://s3-us-west-2.amazonaws.com/kola-fixtures/resources/anonymous"
   168  			      },
   169  			      "mode": 420
   170  			  },
   171  			  {
   172  			      "path": "/var/resource/s3-anon",
   173  			      "contents": {
   174  				  "source": "s3://kola-fixtures/resources/anonymous"
   175  			      },
   176  			      "mode": 420
   177  			  }
   178  		      ]
   179  		  }
   180  	      }`),
   181  		Distros: []string{"cl", "fcos", "rhcos"},
   182  	})
   183  	register.Register(&register.Test{
   184  		Name:        "coreos.ignition.resource.s3",
   185  		Run:         resourceS3,
   186  		ClusterSize: 1,
   187  		Platforms:   []string{"aws"},
   188  		UserData: conf.Ignition(`{
   189  		  "ignition": {
   190  		      "version": "2.1.0",
   191  		      "config": {
   192  		          "append": [{
   193  		              "source": "s3://kola-fixtures/resources/authenticated-var.ign"
   194  		          }]
   195  		      }
   196  		  },
   197  		  "storage": {
   198  		      "files": [
   199  			  {
   200  			      "filesystem": "root",
   201  			      "path": "/var/resource/s3-auth",
   202  			      "contents": {
   203  				  "source": "s3://kola-fixtures/resources/authenticated"
   204  			      },
   205  			      "mode": 420
   206  			  }
   207  		      ]
   208  		  }
   209  	      }`),
   210  		UserDataV3: conf.Ignition(`{
   211  		  "ignition": {
   212  		      "version": "3.0.0",
   213  		      "config": {
   214  		          "merge": [{
   215  		              "source": "s3://kola-fixtures/resources/authenticated-var-v3.ign"
   216  		          }]
   217  		      }
   218  		  },
   219  		  "storage": {
   220  		      "files": [
   221  			  {
   222  			      "path": "/var/resource/s3-auth",
   223  			      "contents": {
   224  				  "source": "s3://kola-fixtures/resources/authenticated"
   225  			      },
   226  			      "mode": 420
   227  			  }
   228  		      ]
   229  		  }
   230  	      }`),
   231  		Distros: []string{"cl", "fcos", "rhcos"},
   232  	})
   233  	// TODO: once Ignition supports this on all channels/distros
   234  	//       this test should be rolled into coreos.ignition.resources.remote
   235  	// Test specifically for versioned s3 objects
   236  	register.Register(&register.Test{
   237  		Name:        "coreos.ignition.resource.s3.versioned",
   238  		Run:         resourceS3Versioned,
   239  		ClusterSize: 1,
   240  		Flags:       []register.Flag{register.RequiresInternetAccess},
   241  		// https://github.com/coreos/bugs/issues/2205 for DO
   242  		ExcludePlatforms: []string{"do"},
   243  		MinVersion:       semver.Version{Major: 1995},
   244  		UserData: conf.Ignition(`{
   245  		  "ignition": {
   246  		      "version": "2.1.0"
   247  		  },
   248  		  "storage": {
   249  		      "files": [
   250  			  {
   251  			      "filesystem": "root",
   252  			      "path": "/var/resource/original",
   253  			      "contents": {
   254  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/versioned?versionId=null"
   255  			      },
   256  			      "mode": 420
   257  			  },
   258  			  {
   259  			      "filesystem": "root",
   260  			      "path": "/var/resource/latest",
   261  			      "contents": {
   262  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/versioned?versionId=RDWqxfnlcJOSDf1.5jy6ZP.oK9Bt7_Id"
   263  			      },
   264  			      "mode": 420
   265  			  }
   266  		      ]
   267  		  }
   268  	      }`),
   269  		UserDataV3: conf.Ignition(`{
   270  		  "ignition": {
   271  		      "version": "3.0.0"
   272  		  },
   273  		  "storage": {
   274  		      "files": [
   275  			  {
   276  			      "path": "/var/resource/original",
   277  			      "contents": {
   278  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/versioned?versionId=null"
   279  			      },
   280  			      "mode": 420
   281  			  },
   282  			  {
   283  			      "path": "/var/resource/latest",
   284  			      "contents": {
   285  				  "source": "http://s3-us-west-2.amazonaws.com/kola-fixtures/resources/versioned?versionId=RDWqxfnlcJOSDf1.5jy6ZP.oK9Bt7_Id"
   286  			      },
   287  			      "mode": 420
   288  			  }
   289  		      ]
   290  		  }
   291  	      }`),
   292  		Distros: []string{"cl", "rhcos"},
   293  	})
   294  }
   295  
   296  func resourceLocal(c cluster.TestCluster) {
   297  	server := c.Machines()[0]
   298  
   299  	c.MustSSH(server, fmt.Sprintf("sudo systemd-run --quiet ./kolet run %s Serve", c.H.Name()))
   300  
   301  	ip := server.PrivateIP()
   302  	if c.Platform() == packet.Platform {
   303  		// private IP not configured in the initramfs
   304  		ip = server.IP()
   305  	}
   306  
   307  	var conf *conf.UserData
   308  	switch c.IgnitionVersion() {
   309  	case "v2":
   310  		conf = localClient
   311  	case "v3":
   312  		conf = localClientV3
   313  	default:
   314  		c.Fatal("unknown ignition version")
   315  	}
   316  
   317  	client, err := c.NewMachine(conf.Subst("$IP", ip))
   318  	if err != nil {
   319  		c.Fatalf("starting client: %v", err)
   320  	}
   321  
   322  	checkResources(c, client, map[string]string{
   323  		"data": "kola-data",
   324  		"http": "kola-http",
   325  		"tftp": "kola-tftp",
   326  	})
   327  }
   328  
   329  func resourceRemote(c cluster.TestCluster) {
   330  	m := c.Machines()[0]
   331  
   332  	checkResources(c, m, map[string]string{
   333  		"http":    "kola-anonymous",
   334  		"https":   "kola-anonymous",
   335  		"s3-anon": "kola-anonymous",
   336  	})
   337  }
   338  
   339  func resourceS3(c cluster.TestCluster) {
   340  	m := c.Machines()[0]
   341  
   342  	checkResources(c, m, map[string]string{
   343  		// object accessible by any authenticated S3 user, such as
   344  		// the IAM role associated with the instance
   345  		"s3-auth": "kola-authenticated",
   346  		// object created by configuration accessible by any authenticated
   347  		// S3 user, such as the IAM role associated with the instance
   348  		"s3-config": "kola-config",
   349  	})
   350  
   351  	// verify that the objects are inaccessible anonymously
   352  	for _, objectName := range []string{"authenticated", "authenticated.ign"} {
   353  		_, _, err := m.SSH("curl -sf https://s3-us-west-2.amazonaws.com/kola-fixtures/resources/" + objectName)
   354  		if err == nil {
   355  			c.Fatal("anonymously fetching authenticated resource should have failed, but did not")
   356  		}
   357  	}
   358  
   359  	// ...but that the anonymous object is accessible
   360  	c.MustSSH(m, "curl -sf https://s3-us-west-2.amazonaws.com/kola-fixtures/resources/anonymous")
   361  }
   362  
   363  func resourceS3Versioned(c cluster.TestCluster) {
   364  	m := c.Machines()[0]
   365  
   366  	checkResources(c, m, map[string]string{
   367  		"original": "original",
   368  		"latest":   "updated",
   369  	})
   370  }
   371  
   372  func checkResources(c cluster.TestCluster, m platform.Machine, resources map[string]string) {
   373  	for filename, expectedContents := range resources {
   374  		contents := c.MustSSH(m, fmt.Sprintf("sudo cat /var/resource/%s", filename))
   375  		if string(contents) != expectedContents {
   376  			c.Fatalf("%s: %q != %q", filename, expectedContents, contents)
   377  		}
   378  	}
   379  }
   380  
   381  func Serve() error {
   382  	go func() {
   383  		http.HandleFunc("/http", func(w http.ResponseWriter, r *http.Request) {
   384  			w.Header().Add("Content-Type", "text/plain")
   385  			w.Write([]byte("kola-http"))
   386  		})
   387  		err := http.ListenAndServe(":80", nil)
   388  		fmt.Println(err)
   389  	}()
   390  
   391  	go func() {
   392  		readHandler := func(filename string, r io.ReaderFrom) error {
   393  			switch filename {
   394  			case "/tftp":
   395  				r.ReadFrom(bytes.NewBufferString("kola-tftp"))
   396  			default:
   397  				return fmt.Errorf("404 not found")
   398  			}
   399  			return nil
   400  		}
   401  		server := tftp.NewServer(readHandler, nil)
   402  		err := server.ListenAndServe(":69")
   403  		fmt.Println(err)
   404  	}()
   405  
   406  	select {}
   407  }