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
|
## redshift
|
||||||
<details>
|
<details>
|
||||||
<summary>28% implemented</summary>
|
<summary>29% implemented</summary>
|
||||||
|
|
||||||
- [ ] accept_reserved_node_exchange
|
- [ ] accept_reserved_node_exchange
|
||||||
- [ ] authorize_cluster_security_group_ingress
|
- [ ] authorize_cluster_security_group_ingress
|
||||||
@ -6789,7 +6789,7 @@
|
|||||||
- [X] disable_snapshot_copy
|
- [X] disable_snapshot_copy
|
||||||
- [ ] enable_logging
|
- [ ] enable_logging
|
||||||
- [X] enable_snapshot_copy
|
- [X] enable_snapshot_copy
|
||||||
- [ ] get_cluster_credentials
|
- [X] get_cluster_credentials
|
||||||
- [ ] get_reserved_node_exchange_offerings
|
- [ ] get_reserved_node_exchange_offerings
|
||||||
- [X] modify_cluster
|
- [X] modify_cluster
|
||||||
- [ ] modify_cluster_db_revision
|
- [ ] modify_cluster_db_revision
|
||||||
|
@ -8,6 +8,7 @@ from boto3 import Session
|
|||||||
from moto.compat import OrderedDict
|
from moto.compat import OrderedDict
|
||||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel
|
from moto.core import BaseBackend, BaseModel, CloudFormationModel
|
||||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||||
|
from moto.utilities.utils import random_string
|
||||||
from moto.ec2 import ec2_backends
|
from moto.ec2 import ec2_backends
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
ClusterAlreadyExistsFaultError,
|
ClusterAlreadyExistsFaultError,
|
||||||
@ -941,6 +942,25 @@ class RedshiftBackend(BaseBackend):
|
|||||||
resource = self._get_resource_from_arn(resource_name)
|
resource = self._get_resource_from_arn(resource_name)
|
||||||
resource.delete_tags(tag_keys)
|
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 = {}
|
redshift_backends = {}
|
||||||
for region in Session().get_available_regions("redshift"):
|
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
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import boto
|
import boto
|
||||||
@ -1487,3 +1488,107 @@ def test_resize_cluster():
|
|||||||
)
|
)
|
||||||
ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue")
|
ex.value.response["Error"]["Code"].should.equal("InvalidParameterValue")
|
||||||
ex.value.response["Error"]["Message"].should.contain("Invalid cluster type")
|
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