fix: add actionable errors for GCE long running operations (#498)

* fix: add actionable errors for GCE long running operations

* add unit test

* mypy

* add notes that the workaround should be removed once proposal A from b/284179390 is implemented

* fix typo

* fix coverage
diff --git a/google/api_core/exceptions.py b/google/api_core/exceptions.py
index 35f2a6f..d4cb997 100644
--- a/google/api_core/exceptions.py
+++ b/google/api_core/exceptions.py
@@ -142,10 +142,21 @@
         self._error_info = error_info
 
     def __str__(self):
+        error_msg = "{} {}".format(self.code, self.message)
         if self.details:
-            return "{} {} {}".format(self.code, self.message, self.details)
+            error_msg = "{} {}".format(error_msg, self.details)
+        # Note: This else condition can be removed once proposal A from
+        # b/284179390 is implemented.
         else:
-            return "{} {}".format(self.code, self.message)
+            if self.errors:
+                errors = [
+                    f"{error.code}: {error.message}"
+                    for error in self.errors
+                    if hasattr(error, "code") and hasattr(error, "message")
+                ]
+                if errors:
+                    error_msg = "{} {}".format(error_msg, "\n".join(errors))
+        return error_msg
 
     @property
     def reason(self):
diff --git a/google/api_core/extended_operation.py b/google/api_core/extended_operation.py
index 79d47f0..d474632 100644
--- a/google/api_core/extended_operation.py
+++ b/google/api_core/extended_operation.py
@@ -158,10 +158,16 @@
                 return
 
             if self.error_code and self.error_message:
+                # Note: `errors` can be removed once proposal A from
+                # b/284179390 is implemented.
+                errors = []
+                if hasattr(self, "error") and hasattr(self.error, "errors"):
+                    errors = self.error.errors
                 exception = exceptions.from_http_status(
                     status_code=self.error_code,
                     message=self.error_message,
                     response=self._extended_operation,
+                    errors=errors,
                 )
                 self.set_exception(exception)
             elif self.error_code or self.error_message:
diff --git a/tests/unit/test_extended_operation.py b/tests/unit/test_extended_operation.py
index c551bfa..53af520 100644
--- a/tests/unit/test_extended_operation.py
+++ b/tests/unit/test_extended_operation.py
@@ -33,11 +33,23 @@
         DONE = 1
         PENDING = 2
 
+    class LROCustomErrors:
+        class LROCustomError:
+            def __init__(self, code: str = "", message: str = ""):
+                self.code = code
+                self.message = message
+
+        def __init__(self, errors: typing.List[LROCustomError] = []):
+            self.errors = errors
+
     name: str
     status: StatusCode
     error_code: typing.Optional[int] = None
     error_message: typing.Optional[str] = None
     armor_class: typing.Optional[int] = None
+    # Note: `error` can be removed once proposal A from
+    # b/284179390 is implemented.
+    error: typing.Optional[LROCustomErrors] = None
 
     # Note: in generated clients, this property must be generated for each
     # extended operation message type.
@@ -170,6 +182,35 @@
     with pytest.raises(exceptions.BadRequest):
         ex_op.result()
 
+    # Test GCE custom LRO Error. See b/284179390
+    # Note: This test case can be removed once proposal A from
+    # b/284179390 is implemented.
+    _EXCEPTION_CODE = "INCOMPATIBLE_BACKEND_SERVICES"
+    _EXCEPTION_MESSAGE = "Validation failed for instance group"
+    responses = [
+        CustomOperation(
+            name=TEST_OPERATION_NAME,
+            status=CustomOperation.StatusCode.DONE,
+            error_code=400,
+            error_message="Bad request",
+            error=CustomOperation.LROCustomErrors(
+                errors=[
+                    CustomOperation.LROCustomErrors.LROCustomError(
+                        code=_EXCEPTION_CODE, message=_EXCEPTION_MESSAGE
+                    )
+                ]
+            ),
+        ),
+    ]
+
+    ex_op, _, _ = make_extended_operation(responses)
+
+    # Defaults to CallError when grpc is not installed
+    with pytest.raises(
+        exceptions.BadRequest, match=f"{_EXCEPTION_CODE}: {_EXCEPTION_MESSAGE}"
+    ):
+        ex_op.result()
+
     # Inconsistent result
     responses = [
         CustomOperation(