github.com/coreos/mantle@v0.13.0/kola/tests/ostree/unlock.go (about)

     1  // Copyright 2018 Red Hat, 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 ostree
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/coreos/mantle/kola/cluster"
    21  	"github.com/coreos/mantle/kola/register"
    22  	"github.com/coreos/mantle/kola/tests/util"
    23  	"github.com/coreos/mantle/platform"
    24  )
    25  
    26  func init() {
    27  	register.Register(&register.Test{
    28  		Run:         ostreeUnlockTest,
    29  		ClusterSize: 1,
    30  		Name:        "ostree.unlock",
    31  		Flags:       []register.Flag{register.RequiresInternetAccess}, // need network to pull RPM
    32  		Distros:     []string{"fcos", "rhcos"},
    33  		FailFast:    true,
    34  	})
    35  	register.Register(&register.Test{
    36  		Run:         ostreeHotfixTest,
    37  		ClusterSize: 1,
    38  		Flags:       []register.Flag{register.RequiresInternetAccess}, // need network to pull RPM
    39  		Name:        "ostree.hotfix",
    40  		Distros:     []string{"fcos", "rhcos"},
    41  		FailFast:    true,
    42  	})
    43  
    44  }
    45  
    46  var (
    47  	rpmUrl  string = "https://raw.githubusercontent.com/projectatomic/atomic-host-tests/master/rpm/aht-dummy-1.0-1.noarch.rpm"
    48  	rpmName string = "aht-dummy"
    49  )
    50  
    51  // ostreeAdminUnlock will unlock the deployment and verify the success of the operation
    52  func ostreeAdminUnlock(c cluster.TestCluster, m platform.Machine, hotfix bool) error {
    53  	var unlockCmd string = "sudo ostree admin unlock"
    54  	if hotfix {
    55  		unlockCmd = "sudo ostree admin unlock --hotfix"
    56  	}
    57  
    58  	_, unlockCmdErr := c.SSH(m, unlockCmd)
    59  	if unlockCmdErr != nil {
    60  		return fmt.Errorf(`Failed to unlock deployment: %v`, unlockCmdErr)
    61  	}
    62  
    63  	status, err := util.GetRpmOstreeStatusJSON(c, m)
    64  	if err != nil {
    65  		c.Fatal(err)
    66  	}
    67  
    68  	if len(status.Deployments) < 1 {
    69  		c.Fatalf(`Did not find any deployments`)
    70  	}
    71  
    72  	// verify that the unlock was successful
    73  	if hotfix && status.Deployments[0].Unlocked != "hotfix" {
    74  		return fmt.Errorf(`Hotfix mode is not reflected in "rpm-ostree status"; got: %q`, status.Deployments[0].Unlocked)
    75  	}
    76  
    77  	if !hotfix && status.Deployments[0].Unlocked != "development" {
    78  		return fmt.Errorf(`Unlocked mode is not reflected in "rpm-ostree status"; got: %q`, status.Deployments[0].Unlocked)
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  // rpmInstallVerify is a small utility func to handle installing an RPM
    85  // and verifying the install was successful
    86  // NOTE: RPM name and binary name must match
    87  func rpmInstallVerify(c cluster.TestCluster, m platform.Machine, rpmFile string, rpmName string) error {
    88  	_, installErr := c.SSH(m, ("sudo rpm -i " + rpmFile))
    89  	if installErr != nil {
    90  		return fmt.Errorf(`Failed to install RPM: %v`, installErr)
    91  	}
    92  
    93  	_, cmdErr := c.SSH(m, ("command -v " + rpmName))
    94  	if cmdErr != nil {
    95  		return fmt.Errorf(`Failed to find binary: %v`, cmdErr)
    96  	}
    97  
    98  	_, rpmErr := c.SSH(m, ("rpm -q " + rpmName))
    99  	if rpmErr != nil {
   100  		return fmt.Errorf(`Failed to find RPM in rpmdb: %v`, rpmErr)
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  // rpmUninstallVerify is a small utility func to handle uninstalling an RPM
   107  // and verifying the uninstall was successful
   108  // NOTE: RPM name and binary name must match
   109  func rpmUninstallVerify(c cluster.TestCluster, m platform.Machine, rpmName string) error {
   110  	_, uninstallErr := c.SSH(m, ("sudo rpm -e " + rpmName))
   111  	if uninstallErr != nil {
   112  		return fmt.Errorf(`Failed to uninstall RPM: %v`, uninstallErr)
   113  	}
   114  
   115  	_, missCmdErr := c.SSH(m, ("command -v " + rpmName))
   116  	if missCmdErr == nil {
   117  		return fmt.Errorf(`Found a binary that should not be there: %v`, missCmdErr)
   118  	}
   119  
   120  	_, missRpmErr := c.SSH(m, ("rpm -q " + rpmName))
   121  	if missRpmErr == nil {
   122  		return fmt.Errorf(`RPM incorrectly in rpmdb after RPM uninstall: %v`, missRpmErr)
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  // ostreeUnlockTest verifies the simplest use of `ostree admin unlock` by
   129  // trying to install a dummy RPM on the host, rebooting, and ensuring
   130  // the RPM is gone after reboot
   131  func ostreeUnlockTest(c cluster.TestCluster) {
   132  	m := c.Machines()[0]
   133  
   134  	// unlock the deployment
   135  	c.Run("unlock", func(c cluster.TestCluster) {
   136  		unlockErr := ostreeAdminUnlock(c, m, false)
   137  		if unlockErr != nil {
   138  			c.Fatal(unlockErr)
   139  		}
   140  	})
   141  
   142  	// try to install an RPM via HTTP
   143  	c.Run("install", func(c cluster.TestCluster) {
   144  		rpmInstallErr := rpmInstallVerify(c, m, rpmUrl, rpmName)
   145  		if rpmInstallErr != nil {
   146  			c.Fatal(rpmInstallErr)
   147  		}
   148  	})
   149  
   150  	// try to uninstall RPM
   151  	c.Run("uninstall", func(c cluster.TestCluster) {
   152  		rpmUninstallErr := rpmUninstallVerify(c, m, rpmName)
   153  		if rpmUninstallErr != nil {
   154  			c.Fatal(rpmUninstallErr)
   155  		}
   156  	})
   157  
   158  	// re-install the RPM and verify the unlocked deployment is discarded
   159  	// after reboot
   160  	c.Run("discard", func(c cluster.TestCluster) {
   161  		c.MustSSH(m, ("sudo rpm -i " + rpmUrl))
   162  
   163  		unlockRebootErr := m.Reboot()
   164  		if unlockRebootErr != nil {
   165  			c.Fatalf("Failed to reboot machine: %v", unlockRebootErr)
   166  		}
   167  
   168  		ros, err := util.GetRpmOstreeStatusJSON(c, m)
   169  		if err != nil {
   170  			c.Fatal(err)
   171  		}
   172  
   173  		if ros.Deployments[0].Unlocked != "none" {
   174  			c.Fatalf(`Deployment was incorrectly unlocked; got: %q`, ros.Deployments[0].Unlocked)
   175  		}
   176  
   177  		_, secCmdErr := c.SSH(m, ("command -v " + rpmName))
   178  		if secCmdErr == nil {
   179  			c.Fatalf(`Binary was incorrectly found after reboot`)
   180  		}
   181  		_, secRpmErr := c.SSH(m, ("rpm -q " + rpmName))
   182  		if secRpmErr == nil {
   183  			c.Fatalf(`RPM incorrectly in rpmdb after reboot`)
   184  		}
   185  	})
   186  }
   187  
   188  // ostreeHotfixTest verifies that the deployment can be put into "hotfix"
   189  // mode, where the RPMs installed will persist across reboots.  A rollback will
   190  // return the host to the original state
   191  func ostreeHotfixTest(c cluster.TestCluster) {
   192  	m := c.Machines()[0]
   193  
   194  	// unlock the deployment into "hotfix" mode
   195  	c.Run("unlock", func(c cluster.TestCluster) {
   196  		unlockErr := ostreeAdminUnlock(c, m, true)
   197  		if unlockErr != nil {
   198  			c.Fatal(unlockErr)
   199  		}
   200  	})
   201  
   202  	// try to install an RPM via HTTP
   203  	c.Run("install", func(c cluster.TestCluster) {
   204  		rpmInstallErr := rpmInstallVerify(c, m, rpmUrl, rpmName)
   205  		if rpmInstallErr != nil {
   206  			c.Fatal(rpmInstallErr)
   207  		}
   208  	})
   209  
   210  	// uninstall the RPM
   211  	c.Run("uninstall", func(c cluster.TestCluster) {
   212  		rpmUninstallErr := rpmUninstallVerify(c, m, rpmName)
   213  		if rpmUninstallErr != nil {
   214  			c.Fatal(rpmUninstallErr)
   215  		}
   216  	})
   217  
   218  	// install the RPM again, reboot, verify it the "hotfix" deployment
   219  	// and RPM have persisted
   220  	c.Run("persist", func(c cluster.TestCluster) {
   221  		c.MustSSH(m, ("sudo rpm -i " + rpmUrl))
   222  
   223  		unlockRebootErr := m.Reboot()
   224  		if unlockRebootErr != nil {
   225  			c.Fatalf("Failed to reboot machine: %v", unlockRebootErr)
   226  		}
   227  
   228  		ros, err := util.GetRpmOstreeStatusJSON(c, m)
   229  		if err != nil {
   230  			c.Fatal(err)
   231  		}
   232  
   233  		if ros.Deployments[0].Unlocked != "hotfix" {
   234  			c.Fatalf(`Hotfix mode was not detected; got: %q`, ros.Deployments[0].Unlocked)
   235  		}
   236  
   237  		c.MustSSH(m, ("command -v " + rpmName))
   238  
   239  		c.MustSSH(m, ("rpm -q " + rpmName))
   240  	})
   241  
   242  	// roll back the deployment and verify the "hotfix" is no longer present
   243  	c.Run("rollback", func(c cluster.TestCluster) {
   244  		c.MustSSH(m, "sudo rpm-ostree rollback")
   245  
   246  		rollbackRebootErr := m.Reboot()
   247  		if rollbackRebootErr != nil {
   248  			c.Fatalf("Failed to reboot machine: %v", rollbackRebootErr)
   249  		}
   250  
   251  		rollbackStatus, err := util.GetRpmOstreeStatusJSON(c, m)
   252  		if err != nil {
   253  			c.Fatal(err)
   254  		}
   255  
   256  		if rollbackStatus.Deployments[0].Unlocked != "none" {
   257  			c.Fatalf(`Rollback did not remove hotfix mode; got: $q`, rollbackStatus.Deployments[0].Unlocked)
   258  		}
   259  
   260  		_, secCmdErr := c.SSH(m, ("command -v " + rpmName))
   261  		if secCmdErr == nil {
   262  			c.Fatalf(`Binary was incorrectly found after reboot`)
   263  		}
   264  		_, secRpmErr := c.SSH(m, ("rpm -q " + rpmName))
   265  		if secRpmErr == nil {
   266  			c.Fatalf(`RPM incorrectly in rpmdb after reboot`)
   267  		}
   268  	})
   269  }