AWS CDK Issue with Appsync - amazon-web-services

import this
from constructs import Construct
from aws_cdk import (
Duration,
Stack,
aws_iam as iam,
aws_appsync as appsync,
aws_dynamodb as dynamodb,
aws_lambda as lamb
)
class CdkStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
api = appsync.GraphqlApi(self, "Api",
name="demo",
schema=appsync.Schema.from_asset('graphql/schema.graphql'),
authorization_config=appsync.AuthorizationConfig(
default_authorization=appsync.AuthorizationMode(
authorization_type=appsync.AuthorizationType.IAM
)
),
xray_enabled=True
)
When I run 'cdk synth' I get the error --> AttributeError: module 'aws_cdk.aws_appsync' has no attribute 'GraphqlApi'. Did you mean: 'CfnGraphQLApi'?
However, GraphqlApi is an attribute in the pypi documentation.

You will find the GraphqlApi construct in the aws_cdk.aws_appsync_alpha package.
Not-yet-stable APIs are in separate "alpha" packages in CDK v2. The Appsync constructs are split between 2 packages, aws_cdk.aws_appsync_alpha for "experimental" APIs, and aws_cdk.aws_appsync for stable APIs.

Related

Cloudformation "update your Lambda function code so that CloudFormation can attach the updated version"

I am deploying the CloudFormation template from this blog post. I had to update the Lambda functions from python 3.6 to 3.9 to get it to work. Now however I get the following error message:
> CloudFormation did not receive a response from your Custom Resource.
> Please check your logs for requestId
> [029f4ea5-cd25-4593-b1ee-d805dd30463f]. If you are using the Python
> cfn-response module, you may need to update your Lambda function code
> so that CloudFormation can attach the updated version.
Below is the lambda code in question - what does it mean to update the Lambda function "so that CloudFormation can attach the updated version"?
import util.cfnresponse
import boto3
import uuid
client = boto3.client('s3')
cfnresponse = util.cfnresponse
def lambda_handler(event, context):
response_data = {}
try:
if event["RequestType"] == "Create":
bucket_name = uuid.uuid4().hex+'-connect'
# response = client.create_bucket(
# Bucket=bucket_name,
# )
response_data["BucketName"] = bucket_name
cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
From what I can tell the response format follows the current version of the response module API?
the cfnrespone lib has changed get updated. Old versions of the lib use the request lib. This CF is over 4 years old so it probably don't work due to this.
You can read about the update on the last rows in the README here:
https://github.com/gene1wood/cfnresponse

How can we calculate the number of Apis exposed through AWS api gateway?

So We have multiple API gateways and in each gateway, we have exposed multiple RESt endpoints. Is there any way to calculate the number of endpoints exposed in each gateway ?
This python script worked for me:
import boto3
from botocore.exceptions import ClientError
import logging
apiGw = boto3.client("apigateway",region_name = "ap-south-1")
def get_rest_api_id():
"""Retrieve the ID of an API Gateway REST API
:return: Retrieved API ID. If API not found or error, returns None.
"""
# Retrieve a batch of APIs
try:
apis = apiGw.get_rest_apis()
except ClientError as e:
logging.error(e)
return None
return apis
apis = get_rest_api_id()["items"]
totalPaths = 0
for api in apis:
response = apiGw.get_resources(
restApiId=api["id"]
)
items = response["items"]
pathCount = len(items)
print(api["name"])
print ("Total Paths = {}".format(pathCount))
totalPaths=totalPaths+pathCount
print("Total Paths : {}".format(totalPaths))
This command should do.
aws apigateway get-rest-apis --no-paginate | jq -r '.items | length'
https://docs.aws.amazon.com/cli/latest/reference/apigateway/get-rest-apis.html
https://stedolan.github.io/jq/

Calling a Django function inside an AWS Lambda

I want to defer some processing load from my Django app to an AWS Lambda.
I'm calling my code from the Lambda like this:
lambda.py:
#bc_lambda(level=logging.INFO, service=LAMBDA_SERVICE)
def task_handler(event, context):
message = event["Records"][0]["body"]
renderer = get_renderer_for(message)
result = renderer.render()
return result
get_renderer_for is a factory method that returns an instance of the class Renderer:
from myproject.apps.engine.documents import (
DocumentsLoader,
SourceNotFound,
source_from_version,
)
from myproject.apps.engine.environment import Environment
class Renderer:
def __init__(self, message):
self.message = message
def render(self):
ENVIRONMENT = Environment(DocumentsLoader())
version_id = self.message.get("version_id")
try:
source = source_from_version(version_id)
except SourceNotFound:
source = None
template = ENVIRONMENT.from_string(source)
if template:
return template.render(self.message)
return None
def get_renderer_for(message):
"""
Factory method that returns an instance of the Renderer class
"""
return Renderer(message)
In CloudWatch, I see I'm getting this error: module initialization error. Apps aren't loaded yet.
I understand that Django is not available for the Lambda function, right? How can I fix this? How can I make the rest of the project available to the lambda function?
The only two libraries that Lambda supports out of the box are the standard library and boto3.
There are several ways to install external Python libraries for use in Lambda. I recommend uploading them as a Lambda layer. This is a good guide: https://medium.com/#qtangs/creating-new-aws-lambda-layer-for-python-pandas-library-348b126e9f3e

How to store Google Auth Credentials object in Django?

I'm trying integrate Google Tag Manager into my project. In official document, Google suggests oauth2client library. Unfortunately, this library deprecated. I used google_auth_oauthlib. I can get token and send request to Google Tag Manager API with this token. But I don't decide how can I store credentials object in Django. In oauth2client lib, there is CredentialsField for model. We can store Credentials object in this field with using DjangoORMStorage. But I can't use this deprecated library. Are there any alternative ways?
Google Tag Manager document is here
My codes here:
from google_auth_oauthlib.flow import Flow
from googleapiclient.discovery import build
FLOW = Flow.from_client_secrets_file(
settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON,
scopes=[settings.GOOGLE_OAUTH2_SCOPE])
class GTMAuthenticateView(APIView):
def get(self,request,**kwargs):
FLOW.redirect_uri = settings.GOOGLE_OAUTH2_REDIRECT_URI
authorization_url, state = FLOW.authorization_url(access_type='offline',
include_granted_scopes='true')
return Response({'authorization_url':authorization_url,'state':state})
def post(self, request, **kwargs):
FLOW.fetch_token(code=request.data['code'])
credentials = FLOW.credentials
return Response({'token':credentials.token})
class GTMContainerView(APIView):
def get(self,request,**kwargs):
service = get_service()
containers = self.get_containers(service)
return Response({'containers':str(containers),'credentials':str(FLOW.credentials)})
#staticmethod
def get_containers(service):
account_list = service.accounts().list().execute()
container_list = []
for account in account_list['account']:
containers = service.accounts().containers().list(parent=account["path"]).execute()
for container in containers["container"]:
container["usageContext"] = container["usageContext"][0].replace("['", "").replace("']", "")
container_list.append(container)
return container_list
def get_service():
try:
credentials = FLOW.credentials
service = build('tagmanager', 'v2', credentials=credentials)
return service
except Exception as ex:
print(ex)
Just switch over to Django 2
pip install Django==2.2.12
I did it and works fine

Required Cloudformation Script for Blue/Green deployment on ECS

I am trying to write a cloud-formation template for AWS ECS with blue green deployment support. This blue-green feature was added recently by AWS in ECS and couldn't find any reference for updating it in cloud-formation template. They have given documentation on, how to do it through UI but not through cloud-formation. I guess, AWS might not updated their cloud-formation documentation as it is a new feature. Any help to find the documentation would be appreciated. Thanking you in advance.
Support for blue/green deployment in CloudFormation has been added. It can be found here in the documentation:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-service-deploymentcontroller.html
In the "Type" property you can choose "CODE_DEPLOY" as the deployment type. Hope this helps!
Currently cloudformation does not support the DeploymentController parameter in which you can specify CODE_DEPLOY.
Keep yourself update by visiting this page for documentation updates:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html
For now - use custom cloudformation resource. Use Boto3 library to create the service with CODE_DEPLOY setting. Read more here:
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecs.html#ECS.Client.create_service
This is the python class which can create/delete/upadte ecs:
import boto3
from botocore.exceptions import ClientError
from typing import Any, Dict
client = boto3.client('ecs')
class Service:
#staticmethod
def create(**kwargs) -> Dict[str, Any]:
kwargs = dict(
cluster=kwargs.get('cluster'),
serviceName=kwargs.get('serviceName'),
taskDefinition=kwargs.get('taskDefinition'),
loadBalancers=kwargs.get('loadBalancers'),
serviceRegistries=kwargs.get('serviceRegistries'),
desiredCount=kwargs.get('desiredCount'),
clientToken=kwargs.get('clientToken'),
launchType=kwargs.get('launchType'),
platformVersion=kwargs.get('platformVersion'),
role=kwargs.get('role'),
deploymentConfiguration=kwargs.get('deploymentConfiguration'),
placementConstraints=kwargs.get('placementConstraints'),
placementStrategy=kwargs.get('placementStrategy'),
networkConfiguration=kwargs.get('networkConfiguration'),
healthCheckGracePeriodSeconds=kwargs.get('healthCheckGracePeriodSeconds'),
schedulingStrategy=kwargs.get('schedulingStrategy'),
deploymentController=kwargs.get('deploymentController'),
tags=kwargs.get('tags'),
enableECSManagedTags=kwargs.get('enableECSManagedTags'),
propagateTags=kwargs.get('propagateTags'),
)
kwargs = {key: value for key, value in kwargs.items() if key and value}
return client.create_service(**kwargs)
#staticmethod
def update(**kwargs: Dict[str, Any]) -> Dict[str, Any]:
filtered_kwargs = dict(
cluster=kwargs.get('cluster'),
service=kwargs.get('serviceName'),
desiredCount=kwargs.get('desiredCount'),
taskDefinition=kwargs.get('taskDefinition'),
deploymentConfiguration=kwargs.get('deploymentConfiguration'),
networkConfiguration=kwargs.get('networkConfiguration'),
platformVersion=kwargs.get('platformVersion'),
forceNewDeployment=kwargs.get('forceNewDeployment'),
healthCheckGracePeriodSeconds=kwargs.get('healthCheckGracePeriodSeconds')
)
try:
filtered_kwargs = {key: value for key, value in filtered_kwargs.items() if key and value}
return client.update_service(**filtered_kwargs)
except ClientError as ex:
if ex.response['Error']['Code'] == 'InvalidParameterException':
if 'use aws codedeploy' in ex.response['Error']['Message'].lower():
# For services using the blue/green (CODE_DEPLOY ) deployment controller,
# only the desired count, deployment configuration, and health check grace period
# can be updated using this API. If the network configuration, platform version, or task definition
# need to be updated, a new AWS CodeDeploy deployment should be created.
filtered_kwargs = dict(
cluster=kwargs.get('cluster'),
service=kwargs.get('serviceName'),
desiredCount=kwargs.get('desiredCount'),
deploymentConfiguration=kwargs.get('deploymentConfiguration'),
healthCheckGracePeriodSeconds=kwargs.get('healthCheckGracePeriodSeconds'),
)
filtered_kwargs = {key: value for key, value in filtered_kwargs.items() if key and value}
return client.update_service(**filtered_kwargs)
elif ex.response['Error']['Code'] == 'ServiceNotActiveException':
# We can not update ecs service if it is inactive.
return {'Code': 'ServiceNotActiveException'}
elif ex.response['Error']['Code'] == 'ServiceNotFoundException':
# If for some reason service was not found - don't update and return.
return {'Code': 'ServiceNotFoundException'}
raise
#staticmethod
def delete(**kwargs: Dict[str, Any]) -> Dict[str, Any]:
kwargs = dict(
cluster=kwargs.get('cluster'),
service=kwargs.get('serviceName'),
force=True
)
kwargs = {key: value for key, value in kwargs.items() if key and value}
return client.delete_service(**kwargs)