Adding Failure Marker to CrOS Provision

BUG=b:199088285
TEST=unit

Change-Id: Ieca99eb1e79d6bd9d70daf24327a408cc7c68168
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/3152196
Tested-by: Jaques Clapauch <jaquesc@google.com>
Auto-Submit: Jaques Clapauch <jaquesc@google.com>
Reviewed-by: Otabek Kasimov <otabek@google.com>
Commit-Queue: Otabek Kasimov <otabek@google.com>
diff --git a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/info/partitioninfo.go b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/info/partitioninfo.go
index a57c78b..d47bc6d 100644
--- a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/info/partitioninfo.go
+++ b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/info/partitioninfo.go
@@ -25,6 +25,12 @@
 const (
 	StatefulPath           = "/mnt/stateful_partition"
 	UpdateStatefulFilePath = StatefulPath + "/.update_available"
+	// ProvisionMarker - This file acts as a flag to signal failed provisions.
+	// As we create the file in stateful, that means that if provision
+	// is successful it will be overwritten, meaning that the fact it exists
+	// beyond a provision run means it must have failed.
+	// This file should be created on every OS provision start.
+	ProvisionMarker = "/var/tmp/provision_failed"
 )
 
 // partitionsInfo holds active/inactive root + kernel partition information.
diff --git a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/crosservice.go b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/crosservice.go
index e6631d8..3337a7e 100644
--- a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/crosservice.go
+++ b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/crosservice.go
@@ -59,6 +59,14 @@
 	The following run specific commands related to CrOS installation.
 */
 
+// Creates a marker, whose existance signals a failure in provisioning
+func (c *CrOSService) CreateProvisionMarker(ctx context.Context) error {
+	if _, err := c.connection.RunCmd(ctx, "touch", []string{info.ProvisionMarker}); err != nil {
+		return fmt.Errorf("failed to create provisionFailed file, %w", err)
+	}
+	return nil
+}
+
 // GetRoot returns the rootdev outoput for root
 func (c *CrOSService) GetRoot(ctx context.Context) (string, error) {
 	// Example 1: "/dev/nvme0n1p3"
diff --git a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/installstate.go b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/installstate.go
index a43cd97..88b4b7f 100644
--- a/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/installstate.go
+++ b/src/chromiumos/test/provision/cmd/provisionserver/bootstrap/services/crosservice/installstate.go
@@ -17,6 +17,10 @@
 }
 
 func (s CrOSInstallState) Execute(ctx context.Context) error {
+	if err := s.service.CreateProvisionMarker(ctx); err != nil {
+		return fmt.Errorf("failed to create provision marker, %s", err)
+	}
+
 	root, err := s.service.GetRoot(ctx)
 	if err != nil {
 		return fmt.Errorf("failed to get root, %s", err)
diff --git a/src/chromiumos/test/provision/cmd/provisionserver/provisionserver_test.go b/src/chromiumos/test/provision/cmd/provisionserver/provisionserver_test.go
index 8aad0b9..aa23a29 100644
--- a/src/chromiumos/test/provision/cmd/provisionserver/provisionserver_test.go
+++ b/src/chromiumos/test/provision/cmd/provisionserver/provisionserver_test.go
@@ -44,6 +44,7 @@
 
 	// Serial Portion
 	gomock.InOrder(
+		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("touch"), gomock.Eq([]string{"/var/tmp/provision_failed"})).Return("", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s"})).Return(fmt.Sprintf("root%s", info.PartitionNumRootA), nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s", "-d"})).Return("root_disk", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("stop"), gomock.Eq([]string{"ui"})).Return("", nil),
@@ -145,6 +146,7 @@
 
 	// Serial Portion
 	gomock.InOrder(
+		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("touch"), gomock.Eq([]string{"/var/tmp/provision_failed"})).Return("", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s"})).Return(fmt.Sprintf("root%s", info.PartitionNumRootA), nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s", "-d"})).Return("root_disk", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("stop"), gomock.Eq([]string{"ui"})).Return("", nil),
@@ -203,6 +205,7 @@
 
 	// Serial Portion
 	gomock.InOrder(
+		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("touch"), gomock.Eq([]string{"/var/tmp/provision_failed"})).Return("", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s"})).Return(fmt.Sprintf("root%s", info.PartitionNumRootA), nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("rootdev"), gomock.Eq([]string{"-s", "-d"})).Return("root_disk", nil),
 		sam.EXPECT().RunCmd(gomock.Any(), gomock.Eq("stop"), gomock.Eq([]string{"ui"})).Return("", nil),