Giter VIP home page Giter VIP logo

terraform-aws-lambda-scheduler-stop-start's Introduction

terraform-aws-lambda-scheduler-stop-start

CI

Stop and start instance, rds resources and autoscaling groups with lambda function.

Terraform versions

For Terraform 0.15 use version v3.* of this module.

If you are using Terraform 0.11 you can use versions v1.*.

Features

  • Aws lambda runtine Python 3.7
  • ec2 instances scheduling
  • ecs service scheduling
  • rds clusters scheduling
  • rds instances scheduling
  • redshift clusters scheduling
  • documentdb clusters scheduling
  • autoscalings scheduling
  • cloudwatch alarm scheduling
  • Aws CloudWatch logs for lambda

Usage

module "stop_ec2_instance" {
  source                         = "diodonfrost/lambda-scheduler-stop-start/aws"
  name                           = "ec2_stop"
  cloudwatch_schedule_expression = "cron(0 0 ? * FRI *)"
  schedule_action                = "stop"
  autoscaling_schedule           = "false"
  documendb_schedule             = "false"
  ec2_schedule                   = "true"
  ecs_schedule                   = "false"
  rds_schedule                   = "false"
  redshift_schedule              = "false"
  cloudwatch_alarm_schedule      = "false"
  scheduler_tag                  = {
    key   = "tostop"
    value = "true"
  }
}

module "start_ec2_instance" {
  source                         = "diodonfrost/lambda-scheduler-stop-start/aws"
  name                           = "ec2_start"
  cloudwatch_schedule_expression = "cron(0 8 ? * MON *)"
  schedule_action                = "start"
  autoscaling_schedule           = "false"
  documendb_schedule             = "false"
  ec2_schedule                   = "true"
  ecs_schedule                   = "false"
  rds_schedule                   = "false"
  redshift_schedule              = "false"
  cloudwatch_alarm_schedule      = "false"
  scheduler_tag                  = {
    key   = "tostop"
    value = "true"
  }
}

Examples

  • Autoscaling scheduler - Create lambda functions to suspend autoscaling group with tag tostop = true and terminate its ec2 instances on Friday at 23:00 Gmt and start them on Monday at 07:00 GMT
  • Documentdb scheduler - Create lambda functions to stop documentdb cluster with tag tostop = true on Friday at 23:00 Gmt and start them on Monday at 07:00 GMT
  • Instance scheduler - Create lambda functions to stop ec2 with tag tostop = true on Friday at 23:00 Gmt and start them on Monday at 07:00 GMT
  • Rds aurora - mariadb scheduler - Create lambda functions to stop rds mariadb and aurora cluster with tag tostop = true on Friday at 23:00 Gmt and start them on Monday at 07:00 GMT
  • test fixture - Deploy environment for testing module

Inputs

Name Description Type Default Required
name Define name to use for lambda function, cloudwatch event and iam role string n/a yes
custom_iam_role_arn Custom IAM role arn for the scheduling lambda string null no
tags Custom tags on aws resources map null no
kms_key_arn The ARN for the KMS encryption key. If this configuration is not provided when environment variables are in use, AWS Lambda uses a default service key string null no
aws_regions A list of one or more aws regions where the lambda will be apply, default use the current region list null no
cloudwatch_schedule_expression The scheduling expression string "cron(0 22 ? * MON-FRI *)" yes
autoscaling_schedule Enable scheduling on autoscaling resources bool "false" no
autoscaling_terminate_instances Terminate instances when autoscaling group is scheduled to stop bool "false" no
documendb_schedule Enable scheduling on documentdb resources bool "false" no
ec2_schedule Enable scheduling on ec2 instance resources bool "false" no
ecs_schedule Enable scheduling on ecs services resources bool "false" no
rds_schedule Enable scheduling on rds resources bool "false" no
redshift_schedule Enable scheduling on redshift resources bool "false" no
cloudwatch_alarm_schedule Enable scheduleding on cloudwatch alarm resources bool "false" no
schedule_action Define schedule action to apply on resources string "stop" yes
scheduler_tag Set the tag to use for identify aws resources to stop or start map {"key" = "tostop", "value" = "true"} yes

Outputs

Name Description
lambda_iam_role_arn The ARN of the IAM role used by Lambda function
lambda_iam_role_name The name of the IAM role used by Lambda function
scheduler_lambda_arn The ARN of the Lambda function
scheduler_lambda_name The name of the Lambda function
scheduler_lambda_invoke_arn The ARN to be used for invoking Lambda function from API Gateway
scheduler_lambda_function_last_modified The date Lambda function was last modified
scheduler_lambda_function_version Latest published version of your Lambda function
scheduler_log_group_name The name of the scheduler log group
scheduler_log_group_arn The Amazon Resource Name (ARN) specifying the log group

Tests

Some of these tests create real resources in an AWS account. That means they cost money to run, especially if you don't clean up after yourself. Please be considerate of the resources you create and take extra care to clean everything up when you're done!

In order to run tests that access your AWS account, you will need to configure your AWS CLI credentials. For example, you could set the credentials as the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Integration tests

Integration tests are realized with python boto3 and pytest modules.

Install Python dependency:

python3 -m pip install -r requirements-dev.txt
# Test python code use by instance scheduler scheduler
python3 -m pytest -n 4 --cov=package tests/integration/test_instance_scheduler.py

# Test python code use by autoscaling scheduler
python3 -m pytest -n 4 --cov=package tests/integration/test_asg_scheduler.py

# Test python code use by rds scheduler
python3 -m pytest -n 8 --cov=package tests/integration/test_rds_scheduler.py

# Test pythn code use by cloudwatch alarm scheduler
python3 -m pytest -n 12 --cov=package tests/integration/test_cloudwatch_alarm_scheduler.py

# Test all python code
python3 -m pytest -n 30 --cov=package tests/integration/

End-to-end tests

This module has been packaged with Terratest to tests this Terraform module.

Install Terratest with depedencies:

# Prerequisite: install Go
cd tests/end-to-end/ && go get ./...

# Test instance scheduler
go test -timeout 30m -v instance_scheduler_test.go aws_invoke_lambda.go

# Test autoscaling scheduler
go test -timeout 30m -v autoscaling_scheduler_test.go aws_invoke_lambda.go

Authors

Modules managed by diodonfrost

Licence

Apache 2 Licensed. See LICENSE for full details.

Resources

terraform-aws-lambda-scheduler-stop-start's People

Contributors

dependabot[bot] avatar diodonfrost avatar jaash7zohz avatar n3mawashi avatar pgrange avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

terraform-aws-lambda-scheduler-stop-start's Issues

Fargate task number reduced to 0

SUMMARY

It would be nice to implement the same logic to reduce the number of Fargate ECS tasks to 0 in a tagged service

ISSUE TYPE

Just the same way we can reduce the number of EC2 instances in the ASG assigned to an ECS cluster it would be of great use to get something similar to reduce the costs of fargate tasks.

Additional context

Great module. It is very usefull.

Support pausing redshift cluster

SUMMARY

Support pausing redshift cluster

ISSUE TYPE
  • Feature Idea
Additional context

Add any other context or screenshots about the feature request here.

I might be able to submit a pull request

Option to run without tags - schedule all the things (tm)

SUMMARY

In some environments, like dedicated dev ones, the tagging is patchy at best - it would be nicer to have a grabby flag where the scheduler will hit anything in can find, rather than what it can find with the configured tags.

ISSUE TYPE
  • Feature Idea
Additional context

Ideal for dedicated low-risk dev environments.

Lambda function cannot write logs to Cloudwatch

SUMMARY

Probably it has been some change on AWS, because a disclaimer shows asking to add a policy to the execution role used by the Lambda function: AWSLambdaBasicExecutionRole

ISSUE TYPE
  • Bug Report
TERRAFORM VERSION
Terraform v0.14.0
+ provider registry.terraform.io/hashicorp/archive v2.1.0
+ provider registry.terraform.io/hashicorp/aws v3.26.0
+ provider registry.terraform.io/hashicorp/local v2.0.0
+ provider registry.terraform.io/hashicorp/null v3.0.0
+ provider registry.terraform.io/hashicorp/random v3.0.1
+ provider registry.terraform.io/hashicorp/template v2.2.0
+ provider registry.terraform.io/terraform-providers/mysql v1.9.0

Your version of Terraform is out of date! The latest version
is 0.14.7. You can update by downloading from https://www.terraform.io/downloads.htm
STEPS TO REPRODUCE

If you deploy de terraform module as is a disclaimer appears when you try to see the logs from the lambda funcions page on aws web console

module "start_environment" {
  count                          = local.settings.schedulling_enabled == false ? 0 : 1
  source                         = "diodonfrost/lambda-scheduler-stop-start/aws"
  name                           = "ec2_start"
  cloudwatch_schedule_expression = local.settings.env_start
  aws_regions                    = [local.settings.aws_region]
  schedule_action                = "start"
  autoscaling_schedule           = "true"
  ec2_schedule                   = "true"
  rds_schedule                   = "true"
  resources_tag = {
    key   = "Environment"
    value = terraform.workspace
  }

  tags = local.tags
}
EXPECTED RESULTS

Be able to watch logs

ACTUAL RESULTS

No logs.
If you manually add the role everything works as expected

Start ECS - allow for variable desiredCount

SUMMARY

Currently, the ecs handler starts a fixed number of 1 tasks (desired count).
Yet, in many cases, a variable number of tasks needs to be started.

Proposal:
Add new environment variable (e.g. ECS_TASK_DESIRED_COUNT) which defaults to 1, but may be set excplicitly to any number > 1

ISSUE TYPE
  • Feature Idea
Additional context

function start (ecs_handlyer.py) passes desiredCount=1 to update_service()

...
def start(self, aws_tags: List[Dict]) -> None:
...
  self.ecs.update_service(
      cluster=cluster_name, service=service_name, desiredCount=1
  )
...

Failing to start ec2 instances

SUMMARY

I've applied the module using terragrunt 0.12 and I've set as TAG key the following:
ec2-scheduler : true

I also set the cloudwatch scheduler to start instances Mon-friday at 08:00 (am) and stop them at 18:00 .

The lambda function to stop the ec2 instances is working well.
The issue comes with the lambda to start the instances. Looking at the logs in lambda , the function can find the ec2 instances with the tag set by me (ec2-scheduler: true) and it shows:
starting instance id_xcxcxcx
starting instance id_dsijdisjdisj

but they don't actually start.

ISSUE TYPE
  • Bug Report
TERRAFORM VERSION

STEPS TO REPRODUCE

Have multiple tags in the ec2 instance and add the following as last one:
ec2-scheduler : true

Wait for the cloudwatch scheduler to start OR run the lambda manually

EXPECTED RESULTS

Ec2 instance to start

ACTUAL RESULTS

Ec2 instances keep being stopped.

Warnings with terraform v0.12.20

Warning: Interpolation-only expressions are deprecated

  on .terraform/modules/lambda-scheduler-stop-start/diodonfrost-terraform-aws-lambda-scheduler-stop-start-61fcfa4/main.tf line 39, in resource "aws_iam_role_policy" "schedule_autoscaling":
  39:   role = "${aws_iam_role.scheduler_lambda.id}"

Terraform 0.11 and earlier required all non-constant expressions to be
provided via interpolation syntax, but this pattern is now deprecated. To
silence this warning, remove the "${ sequence from the start and the }"
sequence from the end of this expression, leaving just the inner expression.

Template interpolation syntax is still used to construct strings from
expressions when the template includes multiple interpolation sequences or a
mixture of literal strings and interpolations. This deprecation applies only
to templates that consist entirely of a single interpolation sequence.

(and 11 more similar warnings elsewhere)


Warning: Quoted type constraints are deprecated

  on .terraform/modules/lambda-scheduler-stop-start/diodonfrost-terraform-aws-lambda-scheduler-stop-start-61fcfa4/variables.tf line 21, in variable "resources_tag":
  21:   type        = "map"

Terraform 0.11 and earlier required type constraints to be given in quotes,
but that form is now deprecated and will be removed in a future version of
Terraform. To silence this warning, remove the quotes around "map" and write
map(string) instead to explicitly indicate that the map elements are strings.


------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Add function to terminate EC2 instances

SUMMARY

In an EKS cluster environment is very common to use spot instances as worker nodes since applications are ephemeral same as the worker nodes(spot/on-demand instances). In order to save costs on development and non-productive environments shutdown/terminate instances that were created by Karpenter/ClusterAutoScaler/ASG nightly and on weekends is very handy since that just stop instances might include .

ISSUE TYPE
  • Create a function to implement "terminate_instances()" boto3 method instead of "stop_instances", that way both options are available to the final user.

In outputs.tf, both lambda_iam_role_arn and lambda_iam_role_name return the arn.

SUMMARY

In outputs.tf, both lambda_iam_role_arn and lambda_iam_role_name return the arn.

ISSUE TYPE
  • Bug Report
TERRAFORM VERSION
Terraform v0.12.26
+ provider.archive v1.3.0
+ provider.aws v3.2.0
STEPS TO REPRODUCE
module "start_ec2_instance" {
  source  = "diodonfrost/lambda-scheduler-stop-start/aws"

  name                           = "ec2_start"
  schedule_action                = "start"
  
  cloudwatch_schedule_expression = var.start_schedule_expression
  autoscaling_schedule           = var.start_autoscaling
  spot_schedule                  = var.start_spot
  ec2_schedule                   = var.start_ec2
  rds_schedule                   = var.start_rds
  resources_tag = {
    key   = var.start_key
    value = var.start_value
  }
}

output "start_iam_role_arn" {
  value = module.start_ec2_instance.lambda_iam_role_arn
}
output "start_iam_role_name" {
  value = module.start_ec2_instance.lambda_iam_role_name
}
EXPECTED RESULTS

start_iam_role_arn = arn:aws:iam::197848513456:role/ec2_start-scheduler-lambda
start_iam_role_name = ec2_start-scheduler-lambda

ACTUAL RESULTS
start_iam_role_arn = arn:aws:iam::197848513456:role/ec2_start-scheduler-lambda
start_iam_role_name = arn:aws:iam::197848513456:role/ec2_start-scheduler-lambda

Documentation: Tag variable is not properly documented in example, needs amending.

SUMMARY

readme.MD

ISSUE TYPE
  • Documentation update
TERRAFORM VERSION
Terraform v0.13.6
+ provider registry.terraform.io/hashicorp/archive v2.1.0
+ provider registry.terraform.io/hashicorp/aws v2.70.0
+ provider registry.terraform.io/hashicorp/local v2.1.0

Your version of Terraform is out of date! The latest version
is 0.14.7. You can update by downloading from https://www.terraform.io/downloads.html
STEPS TO REPRODUCE

run plan or apply using example on Readme.MD

terraform apply
EXPECTED RESULTS

plan and apply to succeed

ACTUAL RESULTS

The error message below.

Error: Unsupported argument

  on rds_hibernation.tf line 10, in module "start_rds_instances":
  10:   scheduler_tag = {

An argument named "scheduler_tag" is not expected here.

the solution is to align examples in the docs with inputs and outputs etc. e.g scheduler_tag should be resources_tag
I attempted to create a branch but do not have push permissions to update the docs in a PR.

Bug: Call to function "filebase64sha256" failed: can't find aws-stop-start-resources.zip

SUMMARY

Hey there!

There's some issue when applying the module and it seems the function filebase64sha256 is being called before the zip file is generated. I found this issue on terraform github (hashicorp/terraform#30042 (comment)) where they say the argument is being inmediatly evaluated before the data source is refreshed. They also point to a possible fix using the output_base64sha256 attribute of the data source itself.

Let me know if you need anything else!

ISSUE TYPE
  • Bug Report
TERRAFORM VERSION
$ terraform --version
Terraform v1.5.4
on linux_amd64
+ provider registry.terraform.io/hashicorp/archive v2.4.0
+ provider registry.terraform.io/hashicorp/aws v5.11.0
STEPS TO REPRODUCE
terraform {
  required_version = ">= 1"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  backend "s3" {
    key = "terraform.tfstate"
  }
}

provider "aws" {
  region = var.region
  default_tags {
    tags = var.default_tags
  }
}

module "scheduler_start" {
  source                         = "diodonfrost/lambda-scheduler-stop-start/aws"
  version                        = "3.4.0"
  name                           = "scheduler_start"
  cloudwatch_schedule_expression = "cron(45 05 ? * MON-FRI *)"
  schedule_action                = "start"
  autoscaling_schedule           = "true"
  ec2_schedule                   = "true"
  rds_schedule                   = "true"
  resources_tag = {
    key   = "scheduled-start-stop"
    value = "true"
  }
}
module "scheduler_stop" {
  source                         = "diodonfrost/lambda-scheduler-stop-start/aws"
  version                        = "3.4.0"
  name                           = "scheduler_stop"
  cloudwatch_schedule_expression = "cron(15 19 ? * MON-FRI *)"
  schedule_action                = "stop"
  autoscaling_schedule           = "true"
  ec2_schedule                   = "true"
  rds_schedule                   = "true"
  resources_tag = {
    key   = "scheduled-start-stop"
    value = "true"
  }

EXPECTED RESULTS

Zip file should be created and then used the hash for the lambda function and apply all the plan correctly.

ACTUAL RESULTS
$ terraform plan -out=plan.tfplan
module.scheduler_start.data.archive_file.this: Reading...
module.scheduler_stop.data.archive_file.this: Reading...
module.scheduler_start.data.archive_file.this: Read complete after 0s [id=b2a47cbbaf1f945be6ca7e9f90bde3d0c63c4359]
module.scheduler_stop.data.archive_file.this: Read complete after 0s [id=b2a47cbbaf1f945be6ca7e9f90bde3d0c63c4359]
module.scheduler_start.data.aws_iam_policy_document.resource_groups_tagging_api: Reading...
module.scheduler_stop.data.aws_iam_policy_document.rds_scheduler: Reading...
module.scheduler_start.data.aws_region.current: Reading...
module.scheduler_start.data.aws_iam_policy_document.ecs_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.autoscaling_group_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.rds_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.rds_scheduler: Read complete after 0s [id=671776352]
module.scheduler_stop.data.aws_region.current: Reading...
module.scheduler_stop.data.aws_iam_policy_document.instance_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.ecs_scheduler: Read complete after 0s [id=1585618646]
module.scheduler_stop.data.aws_iam_policy_document.autoscaling_group_scheduler: Read complete after 0s [id=1070175367]
module.scheduler_stop.data.aws_iam_policy_document.spot_instance_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.rds_scheduler: Read complete after 0s [id=671776352]
module.scheduler_stop.data.aws_iam_policy_document.instance_scheduler: Read complete after 0s [id=1732007687]
module.scheduler_stop.data.aws_region.current: Read complete after 0s [id=eu-west-1]
module.scheduler_start.data.aws_iam_policy_document.resource_groups_tagging_api: Read complete after 0s [id=2844959228]
module.scheduler_start.data.aws_iam_policy_document.cloudwatch_alarm_scheduler: Reading...
module.scheduler_start.data.aws_region.current: Read complete after 0s [id=eu-west-1]
module.scheduler_stop.data.aws_iam_policy_document.ecs_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.redshift_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.spot_instance_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.spot_instance_scheduler: Read complete after 0s [id=1252256245]
module.scheduler_start.data.aws_iam_policy_document.cloudwatch_alarm_scheduler: Read complete after 0s [id=656061252]
module.scheduler_stop.data.aws_iam_policy_document.redshift_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.cloudwatch_alarm_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.ecs_scheduler: Read complete after 0s [id=1585618646]
module.scheduler_start.data.aws_iam_policy_document.autoscaling_group_scheduler: Reading...
module.scheduler_start.data.aws_iam_policy_document.spot_instance_scheduler: Read complete after 0s [id=1252256245]
module.scheduler_start.data.aws_iam_policy_document.redshift_scheduler: Read complete after 0s [id=2237304675]
module.scheduler_start.data.aws_iam_policy_document.autoscaling_group_scheduler: Read complete after 0s [id=1070175367]
module.scheduler_stop.data.aws_iam_policy_document.cloudwatch_alarm_scheduler: Read complete after 0s [id=656061252]
module.scheduler_stop.data.aws_iam_policy_document.redshift_scheduler: Read complete after 0s [id=2237304675]
module.scheduler_stop.data.aws_iam_policy_document.resource_groups_tagging_api: Reading...
module.scheduler_start.data.aws_iam_policy_document.instance_scheduler: Reading...
module.scheduler_stop.data.aws_iam_policy_document.this: Reading...
module.scheduler_start.data.aws_iam_policy_document.this: Reading...
module.scheduler_stop.data.aws_iam_policy_document.resource_groups_tagging_api: Read complete after 0s [id=2844959228]
module.scheduler_start.data.aws_iam_policy_document.this: Read complete after 0s [id=2690255455]
module.scheduler_start.data.aws_iam_policy_document.instance_scheduler: Read complete after 0s [id=1732007687]
module.scheduler_stop.data.aws_iam_policy_document.this: Read complete after 0s [id=2690255455]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
Terraform will perform the following actions:
  # module.scheduler_start.aws_cloudwatch_event_rule.this will be created
  + resource "aws_cloudwatch_event_rule" "this" {
      + arn                 = (known after apply)
      + description         = "Trigger lambda scheduler"
      + event_bus_name      = "default"
      + id                  = (known after apply)
      + is_enabled          = true
      + name                = "trigger-lambda-scheduler-scheduler_start"
      + name_prefix         = (known after apply)
      + schedule_expression = "cron(45 05 ? * MON-FRI *)"
      + tags_all            = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
    }
  # module.scheduler_start.aws_cloudwatch_event_target.this will be created
  + resource "aws_cloudwatch_event_target" "this" {
      + arn            = (known after apply)
      + event_bus_name = "default"
      + id             = (known after apply)
      + rule           = "trigger-lambda-scheduler-scheduler_start"
      + target_id      = (known after apply)
    }
  # module.scheduler_start.aws_cloudwatch_log_group.this will be created
  + resource "aws_cloudwatch_log_group" "this" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + name              = "/aws/lambda/scheduler_start"
      + name_prefix       = (known after apply)
      + retention_in_days = 14
      + skip_destroy      = false
      + tags_all          = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
    }
  # module.scheduler_start.aws_iam_role.this[0] will be created
  + resource "aws_iam_role" "this" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + description           = "Allows Lambda functions to stop and start ec2 and rds resources"
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "scheduler_start-scheduler-lambda"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
      + unique_id             = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.autoscaling_group_scheduler[0] will be created
  + resource "aws_iam_role_policy" "autoscaling_group_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-autoscaling-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:TerminateInstances",
                          + "autoscaling:UpdateAutoScalingGroup",
                          + "autoscaling:TerminateInstanceInAutoScalingGroup",
                          + "autoscaling:SuspendProcesses",
                          + "autoscaling:ResumeProcesses",
                          + "autoscaling:DescribeTags",
                          + "autoscaling:DescribeScalingProcessTypes",
                          + "autoscaling:DescribeAutoScalingInstances",
                          + "autoscaling:DescribeAutoScalingGroups",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.cloudwatch_alarm_scheduler[0] will be created
  + resource "aws_iam_role_policy" "cloudwatch_alarm_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-cloudwatch-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "cloudwatch:EnableAlarmActions",
                          + "cloudwatch:DisableAlarmActions",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.ecs_scheduler[0] will be created
  + resource "aws_iam_role_policy" "ecs_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-ecs-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ecs:UpdateService",
                          + "ecs:DescribeService",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.instance_scheduler[0] will be created
  + resource "aws_iam_role_policy" "instance_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-ec2-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:StopInstances",
                          + "ec2:StartInstances",
                          + "autoscaling:DescribeAutoScalingInstances",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.lambda_logging[0] will be created
  + resource "aws_iam_role_policy" "lambda_logging" {
      + id     = (known after apply)
      + name   = "scheduler_start-lambda-logging"
      + policy = (known after apply)
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.rds_scheduler[0] will be created
  + resource "aws_iam_role_policy" "rds_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-rds-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "rds:StopDBInstance",
                          + "rds:StopDBCluster",
                          + "rds:StartDBInstance",
                          + "rds:StartDBCluster",
                          + "rds:DescribeDBClusters",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.redshift_scheduler[0] will be created
  + resource "aws_iam_role_policy" "redshift_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-redshift-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "redshift:ResumeCluster",
                          + "redshift:PauseCluster",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.resource_groups_tagging_api[0] will be created
  + resource "aws_iam_role_policy" "resource_groups_tagging_api" {
      + id     = (known after apply)
      + name   = "scheduler_start-resource-groups-tagging-api-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "tag:GetResources"
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_iam_role_policy.spot_instance_scheduler[0] will be created
  + resource "aws_iam_role_policy" "spot_instance_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_start-spot-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:TerminateSpotInstances",
                          + "ec2:DescribeInstances",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_start.aws_lambda_function.this will be created
  + resource "aws_lambda_function" "this" {
      + architectures                  = (known after apply)
      + arn                            = (known after apply)
      + filename                       = ".terraform/modules/scheduler_start/aws-stop-start-resources.zip"
      + function_name                  = "scheduler_start"
      + handler                        = "scheduler.main.lambda_handler"
      + id                             = (known after apply)
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 128
      + package_type                   = "Zip"
      + publish                        = false
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + runtime                        = "python3.9"
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = "UK8Fo9D8DgEnYefnPQtpmAcWpLZwjjjS8IYRu5ArjNk="
      + source_code_size               = (known after apply)
      + tags_all                       = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
      + timeout                        = 600
      + version                        = (known after apply)
      + environment {
          + variables = {
              + "AUTOSCALING_SCHEDULE"            = "true"
              + "AUTOSCALING_TERMINATE_INSTANCES" = "false"
              + "AWS_REGIONS"                     = "eu-west-1"
              + "CLOUDWATCH_ALARM_SCHEDULE"       = "false"
              + "DOCUMENTDB_SCHEDULE"             = "false"
              + "EC2_SCHEDULE"                    = "true"
              + "ECS_SCHEDULE"                    = "false"
              + "RDS_SCHEDULE"                    = "true"
              + "REDSHIFT_SCHEDULE"               = "false"
              + "SCHEDULE_ACTION"                 = "start"
              + "TAG_KEY"                         = "scheduled-start-stop"
              + "TAG_VALUE"                       = "true"
            }
        }
    }
  # module.scheduler_start.aws_lambda_permission.this will be created
  + resource "aws_lambda_permission" "this" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "scheduler_start"
      + id                  = (known after apply)
      + principal           = "events.amazonaws.com"
      + source_arn          = (known after apply)
      + statement_id        = "AllowExecutionFromCloudWatch"
      + statement_id_prefix = (known after apply)
    }
  # module.scheduler_stop.aws_cloudwatch_event_rule.this will be created
  + resource "aws_cloudwatch_event_rule" "this" {
      + arn                 = (known after apply)
      + description         = "Trigger lambda scheduler"
      + event_bus_name      = "default"
      + id                  = (known after apply)
      + is_enabled          = true
      + name                = "trigger-lambda-scheduler-scheduler_stop"
      + name_prefix         = (known after apply)
      + schedule_expression = "cron(15 19 ? * MON-FRI *)"
      + tags_all            = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
    }
  # module.scheduler_stop.aws_cloudwatch_event_target.this will be created
  + resource "aws_cloudwatch_event_target" "this" {
      + arn            = (known after apply)
      + event_bus_name = "default"
      + id             = (known after apply)
      + rule           = "trigger-lambda-scheduler-scheduler_stop"
      + target_id      = (known after apply)
    }
  # module.scheduler_stop.aws_cloudwatch_log_group.this will be created
  + resource "aws_cloudwatch_log_group" "this" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + name              = "/aws/lambda/scheduler_stop"
      + name_prefix       = (known after apply)
      + retention_in_days = 14
      + skip_destroy      = false
      + tags_all          = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
    }
  # module.scheduler_stop.aws_iam_role.this[0] will be created
  + resource "aws_iam_role" "this" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + description           = "Allows Lambda functions to stop and start ec2 and rds resources"
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "scheduler_stop-scheduler-lambda"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
      + unique_id             = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.autoscaling_group_scheduler[0] will be created
  + resource "aws_iam_role_policy" "autoscaling_group_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-autoscaling-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:TerminateInstances",
                          + "autoscaling:UpdateAutoScalingGroup",
                          + "autoscaling:TerminateInstanceInAutoScalingGroup",
                          + "autoscaling:SuspendProcesses",
                          + "autoscaling:ResumeProcesses",
                          + "autoscaling:DescribeTags",
                          + "autoscaling:DescribeScalingProcessTypes",
                          + "autoscaling:DescribeAutoScalingInstances",
                          + "autoscaling:DescribeAutoScalingGroups",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.cloudwatch_alarm_scheduler[0] will be created
  + resource "aws_iam_role_policy" "cloudwatch_alarm_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-cloudwatch-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "cloudwatch:EnableAlarmActions",
                          + "cloudwatch:DisableAlarmActions",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.ecs_scheduler[0] will be created
  + resource "aws_iam_role_policy" "ecs_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-ecs-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ecs:UpdateService",
                          + "ecs:DescribeService",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.instance_scheduler[0] will be created
  + resource "aws_iam_role_policy" "instance_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-ec2-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:StopInstances",
                          + "ec2:StartInstances",
                          + "autoscaling:DescribeAutoScalingInstances",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.lambda_logging[0] will be created
  + resource "aws_iam_role_policy" "lambda_logging" {
      + id     = (known after apply)
      + name   = "scheduler_stop-lambda-logging"
      + policy = (known after apply)
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.rds_scheduler[0] will be created
  + resource "aws_iam_role_policy" "rds_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-rds-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "rds:StopDBInstance",
                          + "rds:StopDBCluster",
                          + "rds:StartDBInstance",
                          + "rds:StartDBCluster",
                          + "rds:DescribeDBClusters",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.redshift_scheduler[0] will be created
  + resource "aws_iam_role_policy" "redshift_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-redshift-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "redshift:ResumeCluster",
                          + "redshift:PauseCluster",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.resource_groups_tagging_api[0] will be created
  + resource "aws_iam_role_policy" "resource_groups_tagging_api" {
      + id     = (known after apply)
      + name   = "scheduler_stop-resource-groups-tagging-api-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "tag:GetResources"
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_iam_role_policy.spot_instance_scheduler[0] will be created
  + resource "aws_iam_role_policy" "spot_instance_scheduler" {
      + id     = (known after apply)
      + name   = "scheduler_stop-spot-custom-policy-scheduler"
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:TerminateSpotInstances",
                          + "ec2:DescribeInstances",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role   = (known after apply)
    }
  # module.scheduler_stop.aws_lambda_function.this will be created
  + resource "aws_lambda_function" "this" {
      + architectures                  = (known after apply)
      + arn                            = (known after apply)
      + filename                       = ".terraform/modules/scheduler_stop/aws-stop-start-resources.zip"
      + function_name                  = "scheduler_stop"
      + handler                        = "scheduler.main.lambda_handler"
      + id                             = (known after apply)
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 128
      + package_type                   = "Zip"
      + publish                        = false
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + runtime                        = "python3.9"
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = "UK8Fo9D8DgEnYefnPQtpmAcWpLZwjjjS8IYRu5ArjNk="
      + source_code_size               = (known after apply)
      + tags_all                       = {
          + "builtWith"   = "terraform"
          + "environment" = "pro"
          + "project"     = "acrecenta-pro"
        }
      + timeout                        = 600
      + version                        = (known after apply)
      + environment {
          + variables = {
              + "AUTOSCALING_SCHEDULE"            = "true"
              + "AUTOSCALING_TERMINATE_INSTANCES" = "false"
              + "AWS_REGIONS"                     = "eu-west-1"
              + "CLOUDWATCH_ALARM_SCHEDULE"       = "false"
              + "DOCUMENTDB_SCHEDULE"             = "false"
              + "EC2_SCHEDULE"                    = "true"
              + "ECS_SCHEDULE"                    = "false"
              + "RDS_SCHEDULE"                    = "true"
              + "REDSHIFT_SCHEDULE"               = "false"
              + "SCHEDULE_ACTION"                 = "stop"
              + "TAG_KEY"                         = "scheduled-start-stop"
              + "TAG_VALUE"                       = "true"
            }
        }
    }
  # module.scheduler_stop.aws_lambda_permission.this will be created
  + resource "aws_lambda_permission" "this" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "scheduler_stop"
      + id                  = (known after apply)
      + principal           = "events.amazonaws.com"
      + source_arn          = (known after apply)
      + statement_id        = "AllowExecutionFromCloudWatch"
      + statement_id_prefix = (known after apply)
    }
Plan: 30 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Saved the plan to: plan.tfplan
To perform exactly these actions, run the following command to apply:
    terraform apply "plan.tfplan"
$ terraform apply -input=false plan.tfplan
╷
│ Error: Error in function call
│ 
│   on .terraform/modules/scheduler_start/main.tf line 263, in resource "aws_lambda_function" "this":
│  263:   source_code_hash = filebase64sha256(data.archive_file.this.output_path)
│     ├────────────────
│     │ while calling filebase64sha256(path)
│     │ data.archive_file.this.output_path is ".terraform/modules/scheduler_start/aws-stop-start-resources.zip"
│ 
│ Call to function "filebase64sha256" failed: open
│ .terraform/modules/scheduler_start/aws-stop-start-resources.zip: no such
│ file or directory.
╵
╷
│ Error: Error in function call
│ 
│   on .terraform/modules/scheduler_stop/main.tf line 263, in resource "aws_lambda_function" "this":
│  263:   source_code_hash = filebase64sha256(data.archive_file.this.output_path)
│     ├────────────────
│     │ while calling filebase64sha256(path)
│     │ data.archive_file.this.output_path is ".terraform/modules/scheduler_stop/aws-stop-start-resources.zip"
│ 
│ Call to function "filebase64sha256" failed: open
│ .terraform/modules/scheduler_stop/aws-stop-start-resources.zip: no such
│ file or directory.
╵

Add support for DocumentDB clusters

SUMMARY

As in the title, this is pretty self-explanatory.

ISSUE TYPE
  • Feature Idea
Additional context

Add any other context or screenshots about the feature request here.

Allow a single scheduler instance to work in an organisation

SUMMARY

Currently, if you have an AWS organisation with multiple accounts, the scheduler must be provisioned in each account. This duplicates both provisioning and maintenance.

This feature would ideally:

  • take in an OU or organisation ID
  • either take in or provision a role that has required access
  • iterate through the accounts executing the configured schedulers

Would suggest MVP is to take the cross-account role as provisioning would be quite an advance challenge.

ISSUE TYPE
  • Feature Idea

Bump Python to python3.12

SUMMARY

python3.12

ISSUE TYPE
  • Python version update
ACTUAL RESULTS

creating Lambda Function (stop_rds-schedule): operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: b7bb373a-862e-40c4-b5ad-131e73e4450a, InvalidParameterValueException: The runtime parameter of python3.7 is no longer supported for creating or updating AWS Lambda functions. We recommend you use the new runtime (python3.12) while creating or updating functions.

Disable CloudWatch alarm actions

SUMMARY

Allow to enable/disable cloudwatch alarm actions like it's possible for ec2 instances.

ISSUE TYPE

I'd like to use this module to create scheduled downtime. However, I have several alarms set up, so whenever I stop my instances, I get alerts that something's broken when really it's not. It would be good to be able to disable cloudwatch alarm actions along with instances.

Additional context

Should be possible via:
https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_EnableAlarmActions.html
https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DisableAlarmActions.html

Unwanted Resources Created

SUMMARY

I am currently trying to use the rds scheduler however when running terraform plan its creating resources for I've set as "false" (e.g. ec2_schedule)

ISSUE TYPE
  • Bug Report
TERRAFORM VERSION

1.6.3

STEPS TO REPRODUCE

module "rds_stop_instance" {
source = "diodonfrost/lambda-scheduler-stop-start/aws"
version = "3.5.0"
name = "stop-rds-${var.environment-name}"
cloudwatch_schedule_expression = "cron(0 02 ? * MON *)" # UTC
schedule_action = "stop"
ec2_schedule = "false"
rds_schedule = "true"
autoscaling_schedule = "false"
cloudwatch_alarm_schedule = "false"

resources_tag = {
key = "stop_rds"
value = "true"
}
}

module "rds_start_instance" {
source = "diodonfrost/lambda-scheduler-stop-start/aws"
version = "3.5.0"
name = "stop-rds-${var.environment-name}"
cloudwatch_schedule_expression = "cron(0 07 ? * MON *)" # UTC
schedule_action = "start"
ec2_schedule = "false"
rds_schedule = "true"
autoscaling_schedule = "false"
cloudwatch_alarm_schedule = "false"

resources_tag = {
key = "start_rds"
value = "true"
}
}

EXPECTED RESULTS

Only rds resources to be created

ACTUAL RESULTS

Creates resources set to "false"

Provide more info when Waiter exceed max attemps

SUMMARY

Allow to configure the Waiter Timeouts and add the instance id in the logs to know which is the one that is not being able to start.

ISSUE TYPE
  • Feature Idea
Additional context

The scheduler is not able to start all of the EC2 instances and raises an error

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.