Added redshift.get_cluster_credentials (#3611)
* Added redshift.get_cluster_credentials * Marked endpoint in list * Removed f string from tests * Python 2.7 compat changes * Fixed parameter retrieval * Formatting * Removed try/catch in favor of if * Changed to existing random_string util Co-authored-by: Andrea Amorosi <aamorosi@amazon.es>
This commit is contained in:
parent
d7f218bfec
commit
5a41866f71
@ -6721,7 +6721,7 @@
|
||||
|
||||
## redshift
|
||||
<details>
|
||||
<summary>28% implemented</summary>
|
||||
<summary>29% implemented</summary>
|
||||
|
||||
- [ ] accept_reserved_node_exchange
|
||||
- [ ] authorize_cluster_security_group_ingress
|
||||
@ -6789,7 +6789,7 @@
|
||||
- [X] disable_snapshot_copy
|
||||
- [ ] enable_logging
|
||||
- [X] enable_snapshot_copy
|
||||
- [ ] get_cluster_credentials
|
||||
- [X] get_cluster_credentials
|
||||
- [ ] get_reserved_node_exchange_offerings
|
||||
- [X] modify_cluster
|
||||
- [ ] modify_cluster_db_revision
|
||||
|
@ -8,6 +8,7 @@ from boto3 import Session
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||
from moto.utilities.utils import random_string
|
||||
from moto.ec2 import ec2_backends
|
||||
from .exceptions import (
|
||||
ClusterAlreadyExistsFaultError,
|
||||
@ -941,6 +942,25 @@ class RedshiftBackend(BaseBackend):
|
||||
resource = self._get_resource_from_arn(resource_name)
|
||||
resource.delete_tags(tag_keys)
|
||||
|
||||
def get_cluster_credentials(
|
||||
self, cluster_identifier, db_user, auto_create, duration_seconds
|
||||
):
|
||||
if duration_seconds < 900 or duration_seconds > 3600:
|
||||
raise InvalidParameterValueError(
|
||||
"Token duration must be between 900 and 3600 seconds"
|
||||
)
|
||||
expiration = datetime.datetime.now() + datetime.timedelta(0, duration_seconds)
|
||||
if cluster_identifier in self.clusters:
|
||||
user_prefix = "IAM:" if auto_create is False else "IAMA:"
|
||||
db_user = user_prefix + db_user
|
||||
return {
|
||||
"DbUser": db_user,
|
||||
"DbPassword": random_string(32),
|
||||
"Expiration": expiration,
|
||||
}
|
||||
else:
|
||||
raise ClusterNotFoundError(cluster_identifier)
|
||||
|
||||
|
||||
redshift_backends = {}
|
||||
for region in Session().get_available_regions("redshift"):
|
||||
|
@ -694,3 +694,24 @@ class RedshiftResponse(BaseResponse):
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def get_cluster_credentials(self):
|
||||
cluster_identifier = self._get_param("ClusterIdentifier")
|
||||
db_user = self._get_param("DbUser")
|
||||
auto_create = self._get_bool_param("AutoCreate", False)
|
||||
duration_seconds = self._get_int_param("DurationSeconds", 900)
|
||||
|
||||
cluster_credentials = self.redshift_backend.get_cluster_credentials(
|
||||
cluster_identifier, db_user, auto_create, duration_seconds
|
||||
)
|
||||
|
||||
return self.get_response(
|
||||
{
|
||||
"GetClusterCredentialsResponse": {
|
||||
"GetClusterCredentialsResult": cluster_credentials,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "384ac68d-3775-11df-8963-01868b7c937a"
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import time
|
||||
import datetime
|
||||
|
||||
import boto
|
||||
@ -1487,3 +1488,107 @@ def test_resize_cluster():
|
||||
)
|
||||
ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue")
|
||||
ex.value.response["Error"]["Message"].should.contain("Invalid cluster type")
|
||||
|
||||
|
||||
@mock_redshift
|
||||
def test_get_cluster_credentials_non_existent_cluster():
|
||||
client = boto3.client("redshift", region_name="us-east-1")
|
||||
|
||||
with pytest.raises(ClientError) as ex:
|
||||
client.get_cluster_credentials(ClusterIdentifier="non-existent")
|
||||
ex.value.response["Error"]["Code"].should.equal("ClusterNotFound")
|
||||
ex.value.response["Error"]["Message"].should.match(r"Cluster .+ not found.")
|
||||
|
||||
|
||||
@mock_redshift
|
||||
def test_get_cluster_credentials_non_existent_cluster():
|
||||
client = boto3.client("redshift", region_name="us-east-1")
|
||||
|
||||
with pytest.raises(ClientError) as ex:
|
||||
client.get_cluster_credentials(
|
||||
ClusterIdentifier="non-existent", DbUser="some_user"
|
||||
)
|
||||
ex.value.response["Error"]["Code"].should.equal("ClusterNotFound")
|
||||
ex.value.response["Error"]["Message"].should.match(r"Cluster .+ not found.")
|
||||
|
||||
|
||||
@mock_redshift
|
||||
def test_get_cluster_credentials_invalid_duration():
|
||||
client = boto3.client("redshift", region_name="us-east-1")
|
||||
|
||||
cluster_identifier = "my_cluster"
|
||||
client.create_cluster(
|
||||
ClusterIdentifier=cluster_identifier,
|
||||
ClusterType="single-node",
|
||||
DBName="test",
|
||||
MasterUsername="user",
|
||||
MasterUserPassword="password",
|
||||
NodeType="ds2.xlarge",
|
||||
)
|
||||
|
||||
db_user = "some_user"
|
||||
with pytest.raises(ClientError) as ex:
|
||||
client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser=db_user, DurationSeconds=899
|
||||
)
|
||||
ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue")
|
||||
ex.value.response["Error"]["Message"].should.contain(
|
||||
"Token duration must be between 900 and 3600 seconds"
|
||||
)
|
||||
|
||||
with pytest.raises(ClientError) as ex:
|
||||
client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser=db_user, DurationSeconds=3601
|
||||
)
|
||||
ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue")
|
||||
ex.value.response["Error"]["Message"].should.contain(
|
||||
"Token duration must be between 900 and 3600 seconds"
|
||||
)
|
||||
|
||||
|
||||
@mock_redshift
|
||||
def test_get_cluster_credentials():
|
||||
client = boto3.client("redshift", region_name="us-east-1")
|
||||
|
||||
cluster_identifier = "my_cluster"
|
||||
client.create_cluster(
|
||||
ClusterIdentifier=cluster_identifier,
|
||||
ClusterType="single-node",
|
||||
DBName="test",
|
||||
MasterUsername="user",
|
||||
MasterUserPassword="password",
|
||||
NodeType="ds2.xlarge",
|
||||
)
|
||||
|
||||
expected_expiration = time.mktime(
|
||||
(datetime.datetime.now() + datetime.timedelta(0, 900)).timetuple()
|
||||
)
|
||||
db_user = "some_user"
|
||||
response = client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser=db_user,
|
||||
)
|
||||
response["DbUser"].should.equal("IAM:%s" % db_user)
|
||||
assert time.mktime((response["Expiration"]).timetuple()) == pytest.approx(
|
||||
expected_expiration
|
||||
)
|
||||
response["DbPassword"].should.have.length_of(32)
|
||||
|
||||
response = client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser=db_user, AutoCreate=True
|
||||
)
|
||||
response["DbUser"].should.equal("IAMA:%s" % db_user)
|
||||
|
||||
response = client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser="some_other_user", AutoCreate=False
|
||||
)
|
||||
response["DbUser"].should.equal("IAM:%s" % "some_other_user")
|
||||
|
||||
expected_expiration = time.mktime(
|
||||
(datetime.datetime.now() + datetime.timedelta(0, 3000)).timetuple()
|
||||
)
|
||||
response = client.get_cluster_credentials(
|
||||
ClusterIdentifier=cluster_identifier, DbUser=db_user, DurationSeconds=3000,
|
||||
)
|
||||
assert time.mktime(response["Expiration"].timetuple()) == pytest.approx(
|
||||
expected_expiration
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user