Repository: getmoto/moto

Issue:
Feature Request: Glacier: upload_archive and get_job_output
I am trying to mock simple Glacier calls (creation and deletion of a Glacier vault) and can't find my way around this (despite being able to achieve such simple mocking with S3, creating a Bucket).

It seems that the mocking of Glacier simply isn't taken into account.

Code is as follows:
```python
import boto3
from moto import mock_glacier

with mock_glacier():
    glacier_resource = boto3.resource('glacier', region_name="fake-glacier-region")
    vault = glacier_resource.create_vault(accountId='-', vaultName="fake.glacier.name")
```
And I get the following exception at vault creation: 

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/<...>/test_mock_glacier.py", line 9, in test_simplest
    vault = glacier_resource.create_vault(accountId='-', vaultName="fake.glacier.name")
  File "/<...>/.local/lib/python3.7/site-packages/boto3/resources/factory.py", line 520, in do_action
    response = action(self, *args, **kwargs)
  File "/<...>/.local/lib/python3.7/site-packages/boto3/resources/action.py", line 83, in __call__
    response = getattr(parent.meta.client, operation_name)(*args, **params)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/client.py", line 663, in _make_api_call
    operation_model, request_dict, request_context)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/client.py", line 682, in _make_request
    return self._endpoint.make_request(operation_model, request_dict)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/endpoint.py", line 102, in make_request
    return self._send_request(request_dict, operation_model)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/endpoint.py", line 137, in _send_request
    success_response, exception):
  File "/<...>/.local/lib/python3.7/site-packages/botocore/endpoint.py", line 256, in _needs_retry
    caught_exception=caught_exception, request_dict=request_dict)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/hooks.py", line 356, in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/hooks.py", line 228, in emit
    return self._emit(event_name, kwargs)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/hooks.py", line 211, in _emit
    response = handler(**kwargs)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 183, in __call__
    if self._checker(attempts, response, caught_exception):
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 251, in __call__
    caught_exception)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 277, in _should_retry
    return self._checker(attempt_number, response, caught_exception)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 317, in __call__
    caught_exception)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 223, in __call__
    attempt_number, caught_exception)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/retryhandler.py", line 359, in _check_caught_exception
    raise caught_exception
  File "/<...>/.local/lib/python3.7/site-packages/botocore/endpoint.py", line 200, in _do_get_response
    http_response = self._send(request)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/endpoint.py", line 269, in _send
    return self.http_session.send(request)
  File "/<...>/.local/lib/python3.7/site-packages/botocore/httpsession.py", line 343, in send
    raise EndpointConnectionError(endpoint_url=request.url, error=e)
botocore.exceptions.EndpointConnectionError: Could not connect to the endpoint URL: "https://glacier.fake-glacier-region.amazonaws.com/-/vaults/fake.glacier.name"
```

I am using boto3 v1.17.49 and moto v2.0.8 that I installed using `python3.7 -m pip install 'moto[all]'`


Discussion:
Try using a valid AWS `region_name`, like `us-west-2`.
Thanks, it helped.
But it did not solve the whole problem as I now get the following exception: 
```
botocore.exceptions.ClientError: An error occurred (UnrecognizedClientException) when calling the CreateVault operation: The security token included in the request is invalid.
```

I have set mock `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SECURITY_TOKEN`, `AWS_SESSION_TOKEN` environment variables (with `'testing'` as value) as stated in moto's README. 

-----

I am surprised to come across such problems: having to set a valid region name without having the moto library warning me about such concern but rather by having a botocore exception, having security token-related botocore exception. Shouldn't this be handled by the library if the mock actually was active?
Hi  @EnzoMolion, thanks for raising this!

> having security token-related botocore exception

That's definitely wrong. It looks like there's a bug where we do not intercept the call when the vaultName has a `.` in it. It does work if you use a name without a `.`:
```
with mock_glacier():
    glacier_resource = boto3.resource('glacier', region_name="us-west-1")
    vault = glacier_resource.create_vault(accountId='-', vaultName="fakeglaciername")
```

I'll update the title to reflect this.

With a working vaultName, moto will throw an error if you use an unknown region:
```
glacier_resource = boto3.client('glacier', region_name="fake-region-1")
vault = glacier_resource.create_vault(accountId='1234156789', vaultName="fakeglaciername")
```
```
    @classmethod
    def vault_response(clazz, request, full_url, headers):
        region_name = region_from_glacier_url(full_url)
>       response_instance = GlacierResponse(glacier_backends[region_name])
E       KeyError: 'fake-region-1'

../../moto/glacier/responses.py:34: KeyError
```
Phew, that is comforting. I thought I totally missed something and was not confident here was the place for such request. I am happy this led to raising an actual issue.

I prooftested this on my side and it indeed solves the problem, thanks a lot.

-----

If I may add a feature request, having Glacier's [`upload_archive`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glacier.html#Glacier.Vault.upload_archive) and [`get_job_output`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glacier.html#Glacier.Client.get_job_output) support implemented, that would be delightful ☺ (this seems to me, with `create_vault` and `delete_vault`, part of the core endpoints to be able to test a Glacier-handling script)
Periods are now allowed in vault names as of moto >= 2.0.9.dev6

Will reopen/repurpose this to implement the other methods.
Hi @EnzoMolion, both features were already implemented, actually - the implementation coverage script simply didn't show them. That is now fixed.

Also as an FYI, just in case it's relevant:
There was a bug for ServerMode, where jobs/vaults/archives were always created in 'us-east-1', disregarding the user-specified region. That is now fixed as of moto >= 2.2.8.dev38.

Let us know if we've missed anything.
Hi @bblommers thanks for the follow-up !

I am a bit surprised that this issue is closed as it is about supporting both `upload_archive` and `get_job_output` while #4339 does not add implementation coverage for `get_job_output`. Is it actually implemented?


-----
P.S.: Moto is awesome, thanks for the great job!
Hi @EnzoMolion, happy to hear that Moto is useful for you! 'get_job_output' is implemented - there is a test for it [here](https://github.com/spulec/moto/blob/master/tests/test_glacier/test_glacier_jobs.py#L199:L225). 

Thanks for letting me know about the implementation coverage doc - I'll update that shortly 👍 
Thanks a lot!
I'll look within [moto/tests/](https://github.com/spulec/moto/tree/master/tests) in the future to look for possible "implemented but not documented as implemented" endpoints

Resolving patch:
diff --git a/moto/glacier/models.py b/moto/glacier/models.py
--- a/moto/glacier/models.py
+++ b/moto/glacier/models.py
@@ -224,6 +224,13 @@ def list_jobs(self, vault_name):
         vault = self.get_vault(vault_name)
         return vault.list_jobs()
 
+    def get_job_output(self, vault_name, job_id):
+        vault = self.get_vault(vault_name)
+        if vault.job_ready(job_id):
+            return vault.get_job_output(job_id)
+        else:
+            return None
+
     def upload_archive(self, vault_name, body, description):
         vault = self.get_vault(vault_name)
         return vault.create_archive(body, description)
diff --git a/moto/glacier/responses.py b/moto/glacier/responses.py
--- a/moto/glacier/responses.py
+++ b/moto/glacier/responses.py
@@ -162,14 +162,12 @@ def vault_jobs_output_response(self, request, full_url, headers):
     def _vault_jobs_output_response(self, request, full_url, headers):
         vault_name = full_url.split("/")[-4]
         job_id = full_url.split("/")[-2]
-        vault = self.glacier_backend.get_vault(vault_name)
-        if vault.job_ready(job_id):
-            output = vault.get_job_output(job_id)
-            if isinstance(output, dict):
-                headers["content-type"] = "application/json"
-                return 200, headers, json.dumps(output)
-            else:
-                headers["content-type"] = "application/octet-stream"
-                return 200, headers, output
-        else:
+        output = self.glacier_backend.get_job_output(vault_name, job_id)
+        if output is None:
             return 404, headers, "404 Not Found"
+        if isinstance(output, dict):
+            headers["content-type"] = "application/json"
+            return 200, headers, json.dumps(output)
+        else:
+            headers["content-type"] = "application/octet-stream"
+            return 200, headers, output


Test patch: