[GCE] Don't err when the VM whose bot to manage doesn't exist

Management tasks are triggered every minute, and if necessary the
management task will trigger another task to delete the VM. Occasionally
this task is delayed and only completes after the next management task
has already been scheduled. This results in the second management task
seeing a non-existent VM entity, or a recreated VM entity with a
non-existent GCE instance. In such cases, the management task currently
errs, which is expected and correct behavior, but produces an error
message in the logs making it look unexpected or incorrect. For these
cases, don't err.

Bug: 897355
Change-Id: I276fabb0b96d1e265786334550ed0e1715c6b085
Reviewed-on: https://chromium-review.googlesource.com/c/infra/luci/luci-go/+/1583091
Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
Commit-Queue: smut <smut@google.com>
diff --git a/gce/appengine/backend/bots.go b/gce/appengine/backend/bots.go
index f30000c..f899bdb 100644
--- a/gce/appengine/backend/bots.go
+++ b/gce/appengine/backend/bots.go
@@ -153,10 +153,13 @@
 		ID: task.Id,
 	}
 	switch err := datastore.Get(c, vm); {
+	case err == datastore.ErrNoSuchEntity:
+		return nil
 	case err != nil:
 		return errors.Annotate(err, "failed to fetch VM").Err()
 	case vm.URL == "":
-		return errors.Reason("instance does not exist: %s", vm.URL).Err()
+		logging.Debugf(c, "instance %q does not exist", vm.Hostname)
+		return nil
 	}
 	logging.Debugf(c, "fetching bot %q: %s", vm.Hostname, vm.Swarming)
 	bot, err := getSwarming(c, vm.Swarming).Bot.Get(vm.Hostname).Context(c).Do()
diff --git a/gce/appengine/backend/bots_test.go b/gce/appengine/backend/bots_test.go
index 238512e..9210280 100644
--- a/gce/appengine/backend/bots_test.go
+++ b/gce/appengine/backend/bots_test.go
@@ -209,16 +209,26 @@
 				err := manageBot(c, &tasks.ManageBot{})
 				So(err, ShouldErrLike, "ID is required")
 			})
-
-			Convey("missing", func() {
-				err := manageBot(c, &tasks.ManageBot{
-					Id: "id",
-				})
-				So(err, ShouldErrLike, "failed to fetch VM")
-			})
 		})
 
 		Convey("valid", func() {
+			Convey("deleted", func() {
+				err := manageBot(c, &tasks.ManageBot{
+					Id: "id",
+				})
+				So(err, ShouldBeNil)
+			})
+
+			Convey("creating", func() {
+				datastore.Put(c, &model.VM{
+					ID: "id",
+				})
+				err := manageBot(c, &tasks.ManageBot{
+					Id: "id",
+				})
+				So(err, ShouldBeNil)
+			})
+
 			Convey("error", func() {
 				rt.Handler = func(_ interface{}) (int, interface{}) {
 					return http.StatusConflict, nil