├── .gitattributes
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── ContributorAgreement.txt
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── client
├── .eslintrc.js
├── .jscsrc
├── STYLEGUIDE.md
├── app
│ ├── app.module.js
│ ├── common
│ │ ├── MainController.js
│ │ ├── common-modal
│ │ │ ├── CommonModalController.js
│ │ │ └── common-modal.html
│ │ ├── common.module.js
│ │ ├── directives
│ │ │ ├── cronEditor.html
│ │ │ ├── cronEditor.js
│ │ │ ├── defaultIfEmptyDirective.js
│ │ │ ├── healthStatus.js
│ │ │ ├── jsonDiffPatchDirective.js
│ │ │ ├── loadingOverlay.js
│ │ │ ├── multipleEmails.js
│ │ │ ├── scalingCronEditor.html
│ │ │ ├── scalingCronEditor.js
│ │ │ ├── scalingScheduleEditor.html
│ │ │ ├── scalingScheduleEditor.js
│ │ │ ├── scheduleEditor.html
│ │ │ ├── scheduleEditor.js
│ │ │ ├── scheduleViewer.html
│ │ │ ├── scheduleViewer.js
│ │ │ ├── spinner.js
│ │ │ ├── uniqueAmongDirective.js
│ │ │ └── validJsonDirective.js
│ │ ├── launch-config
│ │ │ ├── asg-size.html
│ │ │ └── launch-config.html
│ │ ├── loginForm.html
│ │ ├── loginForm.js
│ │ ├── models
│ │ │ ├── AutoScalingGroup.js
│ │ │ ├── Deployment.js
│ │ │ ├── DeploymentMap.js
│ │ │ ├── Environment.js
│ │ │ ├── Image.js
│ │ │ └── UpstreamConfig.js
│ │ ├── services
│ │ │ ├── accountMappingService.js
│ │ │ ├── asgService.js
│ │ │ ├── awsService.js
│ │ │ ├── cacheService.js
│ │ │ ├── cachedResourcesService.js
│ │ │ ├── comparisons.js
│ │ │ ├── enumsService.js
│ │ │ ├── environmentDeployService.js
│ │ │ ├── environmentStorageService.js
│ │ │ ├── instancesService.js
│ │ │ ├── linkHeaderService.js
│ │ │ ├── loadBalancerService.js
│ │ │ ├── loading.js
│ │ │ ├── localResourceFactoryService.js
│ │ │ ├── localStorageService.js
│ │ │ ├── modalService.js
│ │ │ ├── releaseNotesService.js
│ │ │ ├── remoteResourceFactoryService.js
│ │ │ ├── resourcesService.js
│ │ │ ├── rolesService.js
│ │ │ ├── schemaValidatorService.js
│ │ │ ├── serviceDiscovery.js
│ │ │ ├── storageServiceFactory.js
│ │ │ ├── taggable.js
│ │ │ ├── targetStateService.js
│ │ │ ├── teamStorageService.js
│ │ │ └── upstreamService.js
│ │ ├── utilities.js
│ │ └── utils
│ │ │ ├── QuerySync.js
│ │ │ └── QuerySync.spec.js
│ ├── compare
│ │ ├── CompareController.js
│ │ ├── compare-objects.html
│ │ ├── compare-services.html
│ │ ├── compare.html
│ │ ├── compare.module.js
│ │ ├── diff-viewer
│ │ │ ├── DiffViewerController.js
│ │ │ └── diff-viewer.html
│ │ ├── directives
│ │ │ ├── serviceCell.html
│ │ │ └── serviceCell.js
│ │ └── services
│ │ │ ├── ResourceComparison.js
│ │ │ ├── ResourceComparison.spec.js
│ │ │ ├── comparableResources.js
│ │ │ ├── serviceComparison.js
│ │ │ └── upstreamService.js
│ ├── configuration
│ │ ├── accounts
│ │ │ ├── AccountController.js
│ │ │ ├── AccountsController.js
│ │ │ ├── account.html
│ │ │ └── accounts.html
│ │ ├── audit
│ │ │ ├── AuditCompareModalController.js
│ │ │ ├── AuditController.js
│ │ │ ├── audit-compare-modal.html
│ │ │ └── audit.html
│ │ ├── clusters
│ │ │ ├── ClusterController.js
│ │ │ ├── ClustersController.js
│ │ │ ├── cluster.html
│ │ │ └── clusters.html
│ │ ├── configuration.module.js
│ │ ├── deployment-maps
│ │ │ ├── DeploymentMapController.js
│ │ │ ├── DeploymentMapCreateController.js
│ │ │ ├── DeploymentMapTargetController.js
│ │ │ ├── DeploymentMapsController.js
│ │ │ ├── copyServerRole.html
│ │ │ ├── copyServerRole.js
│ │ │ ├── deployment-map.html
│ │ │ ├── deployment-maps-create-modal.html
│ │ │ ├── deployment-maps-target-modal.html
│ │ │ └── deployment-maps.html
│ │ ├── em-services
│ │ │ ├── ServiceController.js
│ │ │ ├── ServicesController.js
│ │ │ ├── portService.js
│ │ │ ├── service.html
│ │ │ └── services.html
│ │ ├── environment-types
│ │ │ ├── EnvironmentTypeController.js
│ │ │ ├── EnvironmentTypesController.js
│ │ │ ├── environment-type.html
│ │ │ └── environment-types.html
│ │ ├── export
│ │ │ ├── ExportController.js
│ │ │ └── export.html
│ │ ├── import
│ │ │ ├── ImportController.js
│ │ │ └── import.html
│ │ ├── lbupstreams
│ │ │ ├── lbupstream.html
│ │ │ ├── lbupstreams.html
│ │ │ ├── upstreamViewModel.js
│ │ │ └── upstreamViewModel.spec.js
│ │ ├── load-balancers
│ │ │ ├── LBCloneController.js
│ │ │ ├── LBController.js
│ │ │ ├── LBUpstreamController.js
│ │ │ ├── LBUpstreamsController.js
│ │ │ ├── LBsController.js
│ │ │ ├── lb-clone-modal.html
│ │ │ ├── loadbalancer.html
│ │ │ └── loadbalancers.html
│ │ ├── notification-settings
│ │ │ ├── notificationSettingsEntry.html
│ │ │ ├── notificationSettingsEntry.js
│ │ │ ├── notificationSettingsList.html
│ │ │ └── notificationSettingsList.js
│ │ ├── permissions
│ │ │ ├── PermissionController.js
│ │ │ ├── PermissionsController.js
│ │ │ ├── permission.html
│ │ │ └── permissions.html
│ │ ├── pick-ami
│ │ │ ├── PickAmiController.js
│ │ │ └── pickami-modal.html
│ │ ├── popovers
│ │ │ ├── multiple-values.html
│ │ │ ├── notification-settings-paging.html
│ │ │ └── notification-settings.html
│ │ └── services
│ │ │ ├── arrayItemHashDetectorService.js
│ │ │ ├── deploymentMapConverter.js
│ │ │ ├── lbBulkOperationService.js
│ │ │ ├── permissionsValidationService.js
│ │ │ └── permissionsValidationService.spec.js
│ ├── environments
│ │ ├── dialogs
│ │ │ ├── ASGDetailsModalController.js
│ │ │ ├── CreateEnvironmentController.js
│ │ │ ├── DeployModalController.js
│ │ │ ├── LaunchConfigConfirmationController.js
│ │ │ ├── asg
│ │ │ │ ├── asgDistribution.js
│ │ │ │ ├── asgInstances.html
│ │ │ │ ├── asgInstances.js
│ │ │ │ ├── asgServices.html
│ │ │ │ ├── asgServices.js
│ │ │ │ ├── asgSingleInstance.html
│ │ │ │ ├── asgSingleInstance.js
│ │ │ │ ├── asgSingleService.html
│ │ │ │ ├── asgSingleService.js
│ │ │ │ ├── launchConfigConfirmation.html
│ │ │ │ ├── popovers
│ │ │ │ │ ├── help-disable-service.html
│ │ │ │ │ ├── help-service-ignored.html
│ │ │ │ │ ├── help-service-missing.html
│ │ │ │ │ └── help-service-unexpected.html
│ │ │ │ └── runtime-asg.html
│ │ │ ├── deployment-dry-run-result.html
│ │ │ ├── env-asg-details-modal.html
│ │ │ ├── env-create-environment-modal.html
│ │ │ └── env-deploy-modal.html
│ │ ├── directives
│ │ │ ├── currentDesiredTitle.js
│ │ │ ├── healthChecks.js
│ │ │ ├── lbStatusView.html
│ │ │ ├── lbStatusView.js
│ │ │ ├── serviceDiffWithTargetState.html
│ │ │ └── serviceDiffWithTargetState.js
│ │ ├── environments.module.js
│ │ ├── popovers
│ │ │ └── alert-settings.html
│ │ ├── schedule
│ │ │ ├── ManageEnvironmentScheduleController.js
│ │ │ └── env-manage-schedule.html
│ │ ├── servers
│ │ │ ├── ManageEnvironmentServersController.js
│ │ │ ├── env-manage-servers.html
│ │ │ └── serversView.js
│ │ ├── settings
│ │ │ ├── ManageEnvironmentSettingsController.js
│ │ │ └── env-manage-settings.html
│ │ └── summary
│ │ │ ├── EnvironmentsSummaryController.js
│ │ │ └── env-summary.html
│ ├── operations
│ │ ├── ToggleServiceModalController.js
│ │ ├── amis
│ │ │ ├── OpsAMIsController.js
│ │ │ └── ops-amis.html
│ │ ├── deployments
│ │ │ ├── DeploymentDetailsModalController.js
│ │ │ ├── OpsDeploymentsController.js
│ │ │ ├── ops-deployment-details-modal.html
│ │ │ ├── ops-deployments.html
│ │ │ ├── opsDeploymentsInstances.html
│ │ │ ├── opsDeploymentsInstances.js
│ │ │ ├── opsDeploymentsList.html
│ │ │ └── opsDeploymentsList.js
│ │ ├── maintenance
│ │ │ ├── MainteinanceAddServerModalController.js
│ │ │ ├── OpsMaintenanceController.js
│ │ │ ├── ops-maintenance-addserver-modal.html
│ │ │ └── ops-maintenance.html
│ │ ├── operations.module.js
│ │ ├── ops-toggle-service-modal.html
│ │ ├── popovers
│ │ │ └── instance-deployment-status.html
│ │ ├── service
│ │ │ ├── OpsServiceController.js
│ │ │ ├── OpsServiceInstallcheckModalController.js
│ │ │ ├── ops-service-installcheck-modal.html
│ │ │ └── ops-service.html
│ │ └── upstream
│ │ │ ├── ASGSelectionModalController.js
│ │ │ ├── OpsUpstreamController.js
│ │ │ ├── UpstreamDetailsModalController.js
│ │ │ ├── directives
│ │ │ ├── lbServersStatesCell.html
│ │ │ └── lbServersStatesCell.js
│ │ │ ├── ops-upstream-details-modal.html
│ │ │ ├── ops-upstream.html
│ │ │ └── select-asg-modal.html
│ └── settings
│ │ ├── UserSettingsController.js
│ │ ├── settings.module.js
│ │ └── user-settings-modal.html
├── assets
│ ├── css
│ │ ├── angular-ui-grid.min.css
│ │ ├── angular-ui-tree.min.css
│ │ ├── bootstrap-3.3.5
│ │ │ ├── css
│ │ │ │ ├── bootstrap-theme.css
│ │ │ │ ├── bootstrap-theme.css.map
│ │ │ │ ├── bootstrap-theme.min.css
│ │ │ │ ├── bootstrap.css
│ │ │ │ ├── bootstrap.css.map
│ │ │ │ └── bootstrap.min.css
│ │ │ ├── fonts
│ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ └── js
│ │ │ │ ├── bootstrap.js
│ │ │ │ ├── bootstrap.min.js
│ │ │ │ └── npm.js
│ │ ├── jsondiffpatch.css
│ │ ├── loading-bar.min.css
│ │ ├── select.min.css
│ │ ├── tipped.css
│ │ └── tourist.css
│ ├── images
│ │ ├── activity.gif
│ │ ├── clippy.svg
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── logo.jpg
│ │ └── trainline.svg
│ └── lib
│ │ ├── ace.js
│ │ ├── ajv.min.js
│ │ ├── angular-file-saver.bundle.min.js
│ │ ├── angular-moment.min.js
│ │ ├── backbone-min.js
│ │ ├── ext-searchbox.js
│ │ ├── glob-intersection.js
│ │ ├── jquery.min.js
│ │ ├── linq.min.js
│ │ ├── loading-bar.min.js
│ │ ├── mode-json.js
│ │ ├── select.min.js
│ │ ├── smart-table.min.js
│ │ ├── spin.min.js
│ │ ├── thenBy.min.js
│ │ ├── tipped.js
│ │ ├── tourist.min.js
│ │ ├── ui-ace.js
│ │ ├── ui-ace.min.js
│ │ ├── ui-bootstrap-tpls-2.1.3.min.js
│ │ ├── ui-grid.min.js
│ │ └── worker-json.js
├── bower.json
├── docs
│ ├── css
│ │ ├── print.css
│ │ ├── reset.css
│ │ ├── screen.css
│ │ ├── style.css
│ │ └── typography.css
│ ├── fonts
│ │ ├── DroidSans-Bold.ttf
│ │ └── DroidSans.ttf
│ ├── images
│ │ ├── collapse.gif
│ │ ├── expand.gif
│ │ ├── explorer_icons.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── logo_small.png
│ │ ├── pet_store_api.png
│ │ ├── throbber.gif
│ │ └── wordnik_api.png
│ ├── lang
│ │ ├── en.js
│ │ ├── es.js
│ │ ├── fr.js
│ │ ├── it.js
│ │ ├── ja.js
│ │ ├── pl.js
│ │ ├── pt.js
│ │ ├── ru.js
│ │ ├── tr.js
│ │ ├── translator.js
│ │ └── zh-cn.js
│ ├── lib
│ │ ├── backbone-min.js
│ │ ├── handlebars-2.0.0.js
│ │ ├── highlight.7.3.pack.js
│ │ ├── jquery-1.8.0.min.js
│ │ ├── jquery.ba-bbq.min.js
│ │ ├── jquery.slideto.min.js
│ │ ├── jquery.wiggle.min.js
│ │ ├── jsoneditor.min.js
│ │ ├── marked.js
│ │ ├── swagger-oauth.js
│ │ ├── underscore-min.js
│ │ └── underscore-min.map
│ └── swagger-ui.js
├── gulp
│ ├── build.js
│ ├── conf.js
│ ├── e2e-tests.js
│ ├── eslint.js
│ ├── inject.js
│ ├── scripts.js
│ ├── server.js
│ ├── styles.js
│ ├── unit-tests.js
│ └── watch.js
├── gulpfile.js
├── index.html
├── karma.conf.js
├── npm-shrinkwrap.json
├── package.json
├── protractor.conf.js
├── schema
│ ├── EnvironmentType.schema.json
│ └── LBSettings.schema.json
├── styles
│ ├── app-generated.css
│ └── app.scss
├── test
│ └── lib
│ │ ├── angular-mocks.js
│ │ ├── ngAnimateMock.js
│ │ ├── ngMock.js
│ │ └── ngMockE2E.js
└── yarn.lock
├── contracts
├── em-server.instances.json
└── em-server.json
├── contributors
├── DavidHunt.txt
├── DuncanHall.txt
├── FabioGariglio.txt
├── FilipSobczak.txt
├── JakeCross.txt
└── MichalChaniewski.txt
├── em2
├── README.md
├── config
│ └── accounts
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── readme.md
│ │ ├── serverless.yml
│ │ └── src
│ │ ├── lambdas.js
│ │ └── services
│ │ └── dynamo.js
├── deploy
│ ├── account
│ │ ├── aws_default_network_acl.tf
│ │ ├── aws_default_route_table.tf
│ │ ├── aws_default_security_group.tf
│ │ ├── aws_internet_gateway.tf
│ │ ├── aws_main_route_table_association.tf
│ │ ├── aws_nat_gateway.tf
│ │ ├── aws_route_table.tf
│ │ ├── aws_route_table_association.tf
│ │ ├── aws_subnet.tf
│ │ ├── aws_vpc.tf
│ │ ├── em_provider.tf
│ │ ├── outputs.tf
│ │ ├── remote_state.tf
│ │ └── variables.tf
│ ├── ami
│ │ └── ubuntu_1604
│ │ │ ├── init_ubuntu_1604.sh
│ │ │ └── userdata_ubuntu_1604.sh
│ ├── consul
│ │ ├── README.md
│ │ ├── consul.tf
│ │ ├── outputs.tf
│ │ ├── scripts
│ │ │ ├── debian_consul.service
│ │ │ ├── debian_upstart.conf
│ │ │ ├── install.sh
│ │ │ ├── iptables.sh
│ │ │ ├── rhel_consul.service
│ │ │ ├── rhel_upstart.conf
│ │ │ └── service.sh
│ │ └── variables.tf
│ ├── em-child
│ │ ├── README.md
│ │ ├── aws_iam_role.tf
│ │ ├── aws_iam_role_policy.tf
│ │ ├── aws_security_groups.tf
│ │ ├── consul.tf
│ │ ├── em-provider.tf
│ │ ├── outputs.tf
│ │ ├── scripts
│ │ │ ├── debian_consul.service
│ │ │ ├── debian_upstart.conf
│ │ │ ├── install.sh
│ │ │ ├── iptables.sh
│ │ │ ├── rhel_consul.service
│ │ │ ├── rhel_upstart.conf
│ │ │ └── service.sh
│ │ └── variables.tf
│ ├── em-master
│ │ ├── aws_ami.tf
│ │ ├── aws_app.tf
│ │ ├── aws_cloudwatch_event_rules.tf
│ │ ├── aws_cloudwatch_metric_alarm.tf
│ │ ├── aws_dynamodb_table.tf
│ │ ├── aws_elasticache_cluster.tf
│ │ ├── aws_iam_instance_profile.tf
│ │ ├── aws_iam_role.tf
│ │ ├── aws_iam_role_policy.tf
│ │ ├── aws_lambda_function.tf
│ │ ├── aws_security_group.tf
│ │ ├── aws_sns_topic.tf
│ │ ├── em-provider.tf
│ │ ├── em-terraform-remote-state.tf
│ │ ├── em-variables.tf
│ │ ├── environment-manager.env
│ │ ├── init.sh
│ │ ├── lambda
│ │ │ ├── .eslintignore
│ │ │ ├── .eslintrc.js
│ │ │ ├── .jscsrc
│ │ │ ├── InfraEnvironmentManagerAudit
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── InfraEnvironmentManagerAuditBackup
│ │ │ │ ├── AwsAccount.js
│ │ │ │ ├── DynamoTable.js
│ │ │ │ ├── DynamoTables.js
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── InfraEnvironmentManagerBackup
│ │ │ │ ├── AwsAccount.js
│ │ │ │ ├── DynamoTable.js
│ │ │ │ ├── DynamoTables.js
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── InfraEnvironmentManagerScheduler
│ │ │ │ ├── build.js
│ │ │ │ ├── environment.js
│ │ │ │ ├── index.js
│ │ │ │ ├── local
│ │ │ │ │ ├── config.sample.json
│ │ │ │ │ └── index.js
│ │ │ │ ├── npm-shrinkwrap.json
│ │ │ │ ├── package.json
│ │ │ │ ├── presentation
│ │ │ │ │ ├── reporting.js
│ │ │ │ │ └── reporting.spec.js
│ │ │ │ ├── readme.md
│ │ │ │ ├── scheduler.js
│ │ │ │ └── services
│ │ │ │ │ ├── aws.js
│ │ │ │ │ ├── em.js
│ │ │ │ │ ├── rateLimiter.js
│ │ │ │ │ └── rateLimiter.spec.js
│ │ │ ├── package.json
│ │ │ └── scheduler
│ │ │ │ ├── build.js
│ │ │ │ ├── environment.js
│ │ │ │ ├── index.js
│ │ │ │ ├── local
│ │ │ │ ├── config.sample.json
│ │ │ │ └── index.js
│ │ │ │ ├── npm-shrinkwrap.json
│ │ │ │ ├── package.json
│ │ │ │ ├── presentation
│ │ │ │ ├── reporting.js
│ │ │ │ └── reporting.spec.js
│ │ │ │ ├── readme.md
│ │ │ │ ├── scheduler.js
│ │ │ │ └── services
│ │ │ │ ├── aws.js
│ │ │ │ ├── em.js
│ │ │ │ ├── rateLimiter.js
│ │ │ │ └── rateLimiter.spec.js
│ │ └── scripts
│ │ │ ├── app
│ │ │ ├── em-asg-setup.sh
│ │ │ ├── em-install.sh
│ │ │ └── user-data.tpl
│ │ │ ├── environment-manager-env-variables.sh
│ │ │ └── install_consul.sh
│ ├── scripts
│ │ ├── cda_install.sh
│ │ ├── consul_client_install.sh
│ │ ├── consul_server_install.sh
│ │ └── name_instance.sh
│ └── test
│ │ └── test.tf
└── gateway
│ └── session
│ ├── index.js
│ ├── package.json
│ ├── serverless.yml
│ └── src
│ ├── lambdas.js
│ └── services
│ └── session-service.js
├── gulpfile.js
├── package-lock.json
├── package.json
├── server
├── .eslintignore
├── .eslintrc.js
├── .jscsrc
├── Enums.js
├── api
│ ├── api-utils
│ │ ├── dateUtil.js
│ │ ├── ifNotFound.js
│ │ ├── logicalTableName.js
│ │ ├── notImplemented.js
│ │ ├── requestMetadata.js
│ │ └── requestParam.js
│ ├── controllers
│ │ ├── asgs
│ │ │ └── asgController.js
│ │ ├── audit
│ │ │ └── auditController.js
│ │ ├── config
│ │ │ ├── accounts
│ │ │ │ └── accountsController.js
│ │ │ ├── clusters
│ │ │ │ └── clusterController.js
│ │ │ ├── deployment-maps
│ │ │ │ └── deploymentMapController.js
│ │ │ ├── environment-types
│ │ │ │ └── environmentTypeController.js
│ │ │ ├── environments
│ │ │ │ └── environmentsConfigController.js
│ │ │ ├── export
│ │ │ │ └── exportController.js
│ │ │ ├── import
│ │ │ │ └── importController.js
│ │ │ ├── lb-settings
│ │ │ │ └── lbSettingsController.js
│ │ │ ├── notification-settings
│ │ │ │ └── notificationSettingsController.js
│ │ │ ├── permissions
│ │ │ │ └── permissionsController.js
│ │ │ ├── services
│ │ │ │ └── servicesConfigController.js
│ │ │ └── upstreams
│ │ │ │ └── upstreamsConfigController.js
│ │ ├── deployments
│ │ │ └── deploymentsController.js
│ │ ├── diagnostics
│ │ │ └── diagnosticsController.js
│ │ ├── environments
│ │ │ └── environmentsController.js
│ │ ├── images
│ │ │ └── imagesController.js
│ │ ├── instances
│ │ │ └── instancesController.js
│ │ ├── load-balancer
│ │ │ └── loadBalancerController.js
│ │ ├── package-upload-url
│ │ │ ├── dynamicResponseCreator.js
│ │ │ └── packageUploadUrlController.js
│ │ ├── services
│ │ │ └── servicesController.js
│ │ ├── target-state
│ │ │ └── targetStateController.js
│ │ ├── token
│ │ │ └── tokenController.js
│ │ ├── upstreams
│ │ │ └── upstreamsController.js
│ │ └── user
│ │ │ └── userController.js
│ ├── em-internal
│ │ └── controllers
│ │ │ └── initial-data.js
│ ├── error-handler
│ │ └── defaultErrorHandler.js
│ ├── swagger.yaml
│ └── v1.js
├── appspec.yml
├── commands
│ ├── asg
│ │ ├── EnterAutoScalingGroupInstancesToStandby.js
│ │ ├── ExitAutoScalingGroupInstancesFromStandby.js
│ │ ├── SetAutoScalingGroupSchedule.js
│ │ ├── SetAutoScalingGroupSize.js
│ │ └── UpdateAutoScalingGroup.js
│ ├── aws
│ │ ├── GetAccountByEnvironment.js
│ │ └── SetInstanceMaintenanceMode.js
│ ├── deployments
│ │ ├── CreateAutoScalingGroup.js
│ │ ├── CreateLaunchConfiguration.js
│ │ ├── DeployService.js
│ │ ├── DeploymentCommandHandlerLogger.js
│ │ ├── DeploymentContract.schema.js
│ │ ├── GetInfrastructureRequirements.js
│ │ ├── PreparePackage.js
│ │ ├── PreparePackageCommand.schema.js
│ │ ├── ProvideInfrastructure.js
│ │ ├── PushDeployment.js
│ │ ├── S3PathContract.schema.js
│ │ └── packageMover.js
│ ├── launch-config
│ │ ├── SetLaunchConfiguration.js
│ │ └── launchConfigUpdater.js
│ ├── services
│ │ ├── DeleteTargetState.js
│ │ ├── ToggleTargetStatus.js
│ │ └── UpdateTargetState.js
│ ├── slices
│ │ ├── ToggleSlicesByService.js
│ │ └── ToggleSlicesByUpstream.js
│ ├── utils
│ │ ├── metadata.js
│ │ ├── operationResult.js
│ │ └── toggleSlices.js
│ └── validators
│ │ ├── awsAccountValidator.js
│ │ └── lbUpstreamValidator.js
├── config
│ ├── index.js
│ └── version.js
├── configuration.sample.json
├── deployment
│ ├── code-deploy
│ │ ├── application-start.sh
│ │ ├── application-stop.sh
│ │ ├── before-install.sh
│ │ ├── on-after-install.sh
│ │ └── validate-service.sh
│ └── systemd
│ │ ├── environment-manager-debug.service
│ │ └── environment-manager.service
├── healthchecks
│ └── sensu
│ │ ├── healthchecks.py
│ │ ├── healthchecks.yml
│ │ ├── ping.py
│ │ └── redis.py
├── index.js
├── models
│ ├── AutoScalingGroup.js
│ ├── Deployment.js
│ ├── DeploymentMap.js
│ ├── Environment.js
│ ├── EnvironmentType.js
│ ├── Image.js
│ ├── Instance.js
│ ├── OpsEnvironment.js
│ ├── SecurityGroup.js
│ ├── Service.js
│ └── TaggableMixin.js
├── modules
│ ├── DeploymentLogger.js
│ ├── DeploymentLogsStreamer.js
│ ├── MainServer.js
│ ├── PackagePathProvider.js
│ ├── S3GetObjectRequest.js
│ ├── active-directory-adapter
│ │ ├── activeDirectoryAdapter.mock.js
│ │ ├── activeDirectoryAdapter.prod.js
│ │ ├── activeDirectoryAdapterConfiguration.js
│ │ └── index.js
│ ├── amazon-client
│ │ ├── childAccountClient.js
│ │ ├── masterAccountClient.js
│ │ ├── myIdentity.js
│ │ ├── pages.js
│ │ └── s3Url.js
│ ├── auditLogReader.js
│ ├── authentication.js
│ ├── authentications
│ │ ├── cookieAuthentication.js
│ │ ├── cookieAuthenticationConfiguration.js
│ │ ├── tokenAuthentication.js
│ │ └── tokenAuthenticationConfiguration.js
│ ├── authorization.js
│ ├── authorizer.js
│ ├── authorizers
│ │ ├── allow-authenticated.js
│ │ ├── asgs.js
│ │ ├── deploy-authorizer.js
│ │ ├── deployments.js
│ │ ├── environmentProtection.js
│ │ ├── environments-schedule.js
│ │ ├── environments.js
│ │ ├── index.js
│ │ ├── instances.js
│ │ ├── load-balancer-settings.js
│ │ ├── none.js
│ │ ├── package-upload-url.js
│ │ ├── services.js
│ │ ├── simple.js
│ │ ├── toggle-service-status.js
│ │ ├── toggle-services.js
│ │ ├── toggle-upstreams.js
│ │ └── upstreams.js
│ ├── autoScalingGroupSizePredictor.js
│ ├── awsAccounts.js
│ ├── awsDynamo
│ │ └── dynamodbExpression.js
│ ├── awsResourceNameProvider.js
│ ├── base64.js
│ ├── cacheManager.js
│ ├── cacheRouter.js
│ ├── checkAppPrerequisites.js
│ ├── clientFactories
│ │ ├── IAMRoleClient.js
│ │ ├── SNSTopicClient.js
│ │ ├── autoScalingGroupClientFactory.js
│ │ ├── ec2InstanceClientFactory.js
│ │ ├── iamRoleClientFactory.js
│ │ └── snsTopicClientFactory.js
│ ├── clusterNode.js
│ ├── configuration
│ │ ├── ConfigurationProvider.js
│ │ ├── LocalConfigurationProvider.js
│ │ └── S3ConfigurationProvider.js
│ ├── configurationCache.js
│ ├── consul-client
│ │ ├── clientConfig.mock.js
│ │ ├── clientConfig.prod.js
│ │ └── index.js
│ ├── consul-node
│ │ ├── consul-node-sorting-service.js
│ │ └── consul-node.js
│ ├── consulDataStructures.js
│ ├── consulSecretCache.js
│ ├── cronService.js
│ ├── data-access
│ │ ├── accounts.js
│ │ ├── asgips.js
│ │ ├── cacheManagerEncryptedRedis.js
│ │ ├── cachedSingleAccountDynamoTable.js
│ │ ├── clusters.js
│ │ ├── configEnvironmentTypes.js
│ │ ├── configEnvironments.js
│ │ ├── deploymentMaps.js
│ │ ├── deployments.js
│ │ ├── describeDynamoTable.js
│ │ ├── dynamoAudit.js
│ │ ├── dynamoImport.js
│ │ ├── dynamoItemFilter.js
│ │ ├── dynamoSoftDelete.js
│ │ ├── dynamoTable.js
│ │ ├── dynamoTableCache.js
│ │ ├── dynamoTableDescription.js
│ │ ├── dynamoVersion.js
│ │ ├── encryptedRedisStore.js
│ │ ├── lbSettingsAdapter.js
│ │ ├── lbUpstreamAdapter.js
│ │ ├── loadBalancerSettings.js
│ │ ├── loadBalancerUpstreams.js
│ │ ├── notificationSettings.js
│ │ ├── opsEnvironment.js
│ │ ├── permissions.js
│ │ ├── services.js
│ │ └── singleAccountDynamoTable.js
│ ├── deployment
│ │ ├── DeploymentContract.js
│ │ ├── S3PathContract.js
│ │ ├── deploymentDefinition.js
│ │ ├── deploymentRepository.js
│ │ ├── deploymentValidators.js
│ │ ├── serverRoleDefinition.js
│ │ ├── serviceDefinition.js
│ │ ├── serviceDeploymentDefinition.js
│ │ ├── serviceInstallationDefinition.js
│ │ └── validators
│ │ │ ├── blueGreenDeploymentValidator.js
│ │ │ └── uniqueServiceVersionDeploymentValidator.js
│ ├── ec2-monitor
│ │ └── ec2-monitor-client.js
│ ├── emCrypto.js
│ ├── environment-state
│ │ ├── deleteTargetState.js
│ │ ├── getASGReady.js
│ │ ├── getASGState.js
│ │ ├── getAWSInstances.js
│ │ ├── getAWSInstancesByName.js
│ │ ├── getInstanceState.js
│ │ ├── getOverallServiceHealth.js
│ │ ├── getServiceHealth.js
│ │ ├── getServiceInstallationCheck.js
│ │ ├── getServicesState.js
│ │ ├── healthReporter.js
│ │ ├── serverRoleFilters.js
│ │ └── serviceStateUtils.js
│ ├── environmentDatabase.js
│ ├── errors
│ │ ├── ActiveDirectoryError.class.js
│ │ ├── AutoScalingGroupAlreadyExistsError.class.js
│ │ ├── AutoScalingGroupNotFoundError.class.js
│ │ ├── AwsError.class.js
│ │ ├── BadRequestError.class.js
│ │ ├── BaseError.class.js
│ │ ├── ConfigurationError.class.js
│ │ ├── DeploymentValidationError.class.js
│ │ ├── DynamoItemNotFoundError.class.js
│ │ ├── HttpRequestError.class.js
│ │ ├── ImageNotFoundError.class.js
│ │ ├── InconsistentSlicesStatusError.class.js
│ │ ├── InstanceNotFoundError.class.js
│ │ ├── InstanceProfileNotFoundError.class.js
│ │ ├── InvalidContractError.class.js
│ │ ├── InvalidCredentialsError.class.js
│ │ ├── InvalidItemSchemaError.class.js
│ │ ├── InvalidOperationError.class.js
│ │ ├── KeyPairNotFoundError.class.js
│ │ ├── LaunchConfigurationAlreadyExistsError.class.js
│ │ ├── PackagePreparationError.class.js
│ │ ├── ResourceLockedError.js
│ │ ├── ResourceNotFoundError.class.js
│ │ ├── RoleNotFoundError.class.js
│ │ └── TopicNotFoundError.class.js
│ ├── express-middleware
│ │ ├── deprecateMiddleware.js
│ │ ├── loggingMiddleware.js
│ │ ├── swaggerAuthorizerMiddleware.js
│ │ └── swaggerNewRelicMiddleware.js
│ ├── factories
│ │ └── keypairFactory.js
│ ├── functional.js
│ ├── health-checks
│ │ ├── index.js
│ │ ├── library
│ │ │ ├── ping.js
│ │ │ └── redis.js
│ │ └── resultCodes.js
│ ├── http-server-factory
│ │ ├── HttpServerFactory.js
│ │ ├── HttpsServerFactory.js
│ │ └── index.js
│ ├── httpHealthChecks.js
│ ├── logger.js
│ ├── machineImage
│ │ └── imageSummary.js
│ ├── memoize.js
│ ├── merge.js
│ ├── miniStack.js
│ ├── monitoring
│ │ ├── DeploymentMonitor.js
│ │ ├── DeploymentMonitorScheduler.js
│ │ └── activeDeploymentsStatusProvider.js
│ ├── new-relic
│ │ └── check.js
│ ├── promiseUtil.js
│ ├── provisioning
│ │ ├── Image.class.js
│ │ ├── autoScaling
│ │ │ ├── subnetsProvider.js
│ │ │ ├── tagsProvider.js
│ │ │ └── topicNotificationMappingProvider.js
│ │ ├── autoScalingTemplatesProvider.js
│ │ ├── infrastructureConfigurationProvider.js
│ │ ├── launchConfiguration
│ │ │ ├── UserDataBuilder.js
│ │ │ ├── iamInstanceProfileNameProvider.js
│ │ │ ├── imageProvider.js
│ │ │ ├── instanceDevicesProvider.js
│ │ │ ├── keyNameProvider.js
│ │ │ ├── securityGroupsProvider.js
│ │ │ ├── userData
│ │ │ │ ├── linux-user-data.txt
│ │ │ │ └── windows-user-data.txt
│ │ │ └── userDataProvider.js
│ │ ├── launchConfigurationTemplatesProvider.js
│ │ └── namingConventionProvider.js
│ ├── queryHandlersUtil
│ │ ├── applyFuncToAccounts.js
│ │ ├── deployments-helper.js
│ │ ├── getASG.js
│ │ ├── getSlices.js
│ │ ├── scanCrossAccount.js
│ │ └── scanCrossAccountFn.js
│ ├── remoteCacheFlush.js
│ ├── renderer.js
│ ├── resourceFactories
│ │ ├── AsgLifeCycleHooksResource.js
│ │ ├── AsgResource.js
│ │ ├── AsgResourceBase.js
│ │ ├── AsgScheduledActionsResource.js
│ │ ├── InstanceResourceBase.js
│ │ ├── SecurityGroupResource.js
│ │ ├── asgLifeCycleHooksResourceFactory.js
│ │ ├── asgResourceFactory.js
│ │ ├── asgScheduledActionsResourceFactory.js
│ │ ├── ec2ImageResourceFactory.js
│ │ ├── ec2InstanceResourceFactory.js
│ │ ├── iamInstanceProfileResourceFactory.js
│ │ ├── keyPairResourceFactory.js
│ │ ├── launchConfigurationResourceFactory.js
│ │ ├── nginxUpstreamsResourceFactory.js
│ │ └── securityGroupResourceFactory.js
│ ├── s3PackageLocator.js
│ ├── scheduling
│ │ ├── index.js
│ │ └── parseSchedule.js
│ ├── schema
│ │ ├── AccountName.json
│ │ ├── AccountNumber.json
│ │ ├── ConsulConnectCommon.json
│ │ ├── ConsulKey.json
│ │ ├── EnvironmentName.json
│ │ ├── GetTargetStateQuery.json
│ │ ├── UpdateTargetStateCommand.json
│ │ └── schema.js
│ ├── sender.js
│ ├── serverFactoryConfiguration.js
│ ├── service-discovery
│ │ ├── consul
│ │ │ ├── consulCatalog.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── service-targets
│ │ ├── consul
│ │ │ ├── ConsulManager.js
│ │ │ ├── consulMacroManager.js
│ │ │ ├── index.js
│ │ │ └── keyValueStore.js
│ │ └── index.js
│ ├── serviceName.js
│ ├── simple-http.js
│ ├── sns
│ │ └── EnvironmentManagerEvents
│ │ │ ├── createEvent.js
│ │ │ ├── createTopic.js
│ │ │ ├── getTargetArn.js
│ │ │ ├── index.js
│ │ │ └── publishEvent.js
│ ├── sslComponentsRepository
│ │ ├── index.js
│ │ ├── sslComponentsRepository.mock.js
│ │ ├── sslComponentsRepository.prod.config.js
│ │ └── sslComponentsRepository.prod.js
│ ├── systemUser.js
│ ├── toggleServiceStatus.js
│ ├── user-service
│ │ ├── index.js
│ │ ├── userService.mock.js
│ │ └── userService.prod.js
│ ├── user.js
│ ├── userRolesProvider.js
│ ├── userSessionStore.js
│ ├── utilities.js
│ ├── validate
│ │ ├── index.js
│ │ └── rule
│ │ │ ├── environmentExists.js
│ │ │ └── serviceExists.js
│ └── weblink.js
├── package-lock.json
├── package.json
├── queryHandlers
│ ├── GetASGState.js
│ ├── GetAutoScalingGroup.js
│ ├── GetAutoScalingGroupLifeCycleHooks.js
│ ├── GetAutoScalingGroupScheduleStatus.js
│ ├── GetAutoScalingGroupScheduledActions.js
│ ├── GetAutoScalingGroupSize.js
│ ├── GetEnvironmentScheduleStatus.js
│ ├── GetInstanceProfile.js
│ ├── GetKeyPair.js
│ ├── GetLaunchConfiguration.js
│ ├── GetRole.js
│ ├── GetServicePortConfig.js
│ ├── GetTopic.js
│ ├── ScanAutoScalingGroups.js
│ ├── ScanCrossAccountAutoScalingGroups.js
│ ├── ScanCrossAccountImages.js
│ ├── ScanCrossAccountInstances.js
│ ├── ScanImages.js
│ ├── ScanInstances.js
│ ├── ScanInstancesScheduleStatus.js
│ ├── ScanLaunchConfigurations.js
│ ├── ScanNginxUpstreams.js
│ ├── ScanSecurityGroups.js
│ ├── ScanServersStatus.js
│ ├── deployments
│ │ └── GetNodeDeploymentLog.js
│ ├── services
│ │ ├── GetAllNodes.js
│ │ ├── GetNode.js
│ │ ├── GetServerRoles.js
│ │ └── GetTargetState.js
│ └── slices
│ │ ├── GetSlicesByService.js
│ │ └── GetSlicesByUpstream.js
├── routes
│ ├── deploymentNodeLogs.js
│ └── home.js
├── scripts
│ ├── actionDefinitions.js
│ ├── cleanup.js
│ ├── command.js
│ └── preinstall.js
├── start
├── test
│ ├── .eslintrc.js
│ ├── bootstrap.js
│ ├── commandHandlers
│ │ ├── GetAccountByEnvironmentTest.js
│ │ ├── deployment
│ │ │ ├── CreateAutoScalingGroupTest.js
│ │ │ ├── CreateLaunchConfigurationCommandHandler.class.spec.js
│ │ │ ├── DeployServiceTest.js
│ │ │ └── GetInfrastructureRequirementsTest.js
│ │ ├── enterAutoScalingGroupInstancesToStandbyTest.js
│ │ ├── exitAutoScalingGroupInstancesFromStandbyTest.js
│ │ ├── launchConfigUpdater.spec.js
│ │ ├── services
│ │ │ └── ToggleTargetStatusTest.js
│ │ ├── setAutoScalingGroupScheduleCommandHandlerTest.js
│ │ └── validators
│ │ │ ├── awsAccountValidatorTest.js
│ │ │ └── lbUpstreamDynamoResourceValidatorTest.js
│ ├── commands
│ │ ├── asg
│ │ │ └── SetAutoScalingGroupScheduleTest.js
│ │ └── deployments
│ │ │ └── packageMoverTests.js
│ ├── models
│ │ ├── AutoScalingGroupTest.js
│ │ └── InstanceTest.js
│ ├── modules
│ │ ├── DeploymentLoggerTest.js
│ │ ├── DeploymentLogsStreamerTest.js
│ │ ├── DeploymentMonitorTest.js
│ │ ├── PackagePathProviderTest.js
│ │ ├── amazon-client
│ │ │ ├── pagesTest.js
│ │ │ └── s3UrlTest.js
│ │ ├── authorizer.spec.js
│ │ ├── authorizers
│ │ │ ├── environmentProtectedTest.js
│ │ │ └── instances.spec.js
│ │ ├── autoScalingGroupSizePredictorTest.js
│ │ ├── awsDynamo
│ │ │ └── dynamodbExpressionTest.js
│ │ ├── base64Test.js
│ │ ├── cacheTest.js
│ │ ├── clientFactories
│ │ │ └── ConsulManagerTest.js
│ │ ├── consul-node
│ │ │ ├── consul-node-sorting-service.spec.js
│ │ │ └── data.js
│ │ ├── consulDataStructuresTests.js
│ │ ├── data-access
│ │ │ ├── cacheManagerEncryptedRedisTest.js
│ │ │ ├── deploymentsTest.js
│ │ │ ├── describeDynamoTableTest.js
│ │ │ ├── dynamoAuditTest.js
│ │ │ ├── dynamoItemFilterTest.js
│ │ │ ├── dynamoTableCacheTest.js
│ │ │ ├── dynamoTableDescriptionTest.js
│ │ │ ├── dynamoTableTest.js
│ │ │ └── dynamoVersionTest.js
│ │ ├── deployment
│ │ │ ├── deploymentDefinitionTest.js
│ │ │ ├── serverRoleDefinitionTest.js
│ │ │ ├── serviceDefinitionTest.js
│ │ │ ├── serviceInstallationDefinitionTest.js
│ │ │ └── validators
│ │ │ │ ├── BlueGreenDeploymentValidatorTest.js
│ │ │ │ └── UniqueServiceVersionDeploymentValidatorTest.js
│ │ ├── em-services
│ │ │ └── servicesConfigController.spec.js
│ │ ├── emCryptoTest.js
│ │ ├── environment-state
│ │ │ ├── deleteTargetStateTest.js
│ │ │ ├── getASGStateTest.js
│ │ │ ├── getInstanceStateTest.js
│ │ │ ├── healthReporterTests.js
│ │ │ ├── serverInstallCheckTests.js
│ │ │ ├── serverRoleFiltersTest.js
│ │ │ └── serviceStateUtilsTest.js
│ │ ├── express-middleware
│ │ │ └── swaggerAuthorizerMiddlewareTest.js
│ │ ├── instances.spec.js
│ │ ├── logger.spec.js
│ │ ├── machineImage
│ │ │ └── imageSummaryTest.js
│ │ ├── memoizeTest.js
│ │ ├── mergeTest.js
│ │ ├── miniStackTest.js
│ │ ├── promiseUtil.spec.js
│ │ ├── provisioning
│ │ │ ├── AutoScalingTemplatesProvider.spec.js
│ │ │ ├── LaunchConfigurationTemplatesProvider.spec.js
│ │ │ ├── NamingConventionProvider.spec.js
│ │ │ ├── autoScaling
│ │ │ │ ├── SubnetsProvider.spec.js
│ │ │ │ ├── TagsProvider.spec.js
│ │ │ │ └── TopicNotificationMappingProvider.spec.js
│ │ │ ├── infrastructureConfigurationProvider.spec.js
│ │ │ └── launchConfiguration
│ │ │ │ ├── IamInstanceProfileNameProviderTest.js
│ │ │ │ ├── ImageProviderTest.js
│ │ │ │ ├── InstanceDevicesProviderTest.js
│ │ │ │ ├── KeyNameProviderTest.js
│ │ │ │ ├── SecurityGroupsProviderTest.js
│ │ │ │ ├── UserDataBuilderTest.js
│ │ │ │ └── UserDataProviderTest.js
│ │ ├── queryHandlersUtil
│ │ │ ├── deployments-helperTest.js
│ │ │ └── scanCrossAccountFnTest.js
│ │ ├── remoteCacheFlushTest.js
│ │ ├── resourceFactories
│ │ │ ├── AsgResourceBaseTest.js
│ │ │ └── ec2InstanceResourceFactoryTest.js
│ │ ├── s3PackageLocatorTest.js
│ │ ├── scheduling-expectedActions.spec.js
│ │ ├── scheduling-expectedStates.spec.js
│ │ ├── schema
│ │ │ └── schemaTest.js
│ │ ├── service-reporter
│ │ │ └── service-reporterTest.js
│ │ ├── service-updater
│ │ │ └── service-updaterTest.js
│ │ ├── sns
│ │ │ └── EnvironmentManagerEvents
│ │ │ │ ├── createEvent.spec.js
│ │ │ │ ├── createTopic.spec.js
│ │ │ │ ├── getTargetArn.spec.js
│ │ │ │ └── publishEvent.spec.js
│ │ ├── toggleServiceStatus.spec.js
│ │ ├── userRolesProviderTest.js
│ │ ├── utilitiesTest.js
│ │ ├── validate
│ │ │ └── validateTest.js
│ │ └── weblinkTest.js
│ ├── queryHandlers
│ │ ├── GetServicePortTest.js
│ │ ├── ScanCrossAccountImagesTest.js
│ │ └── ScanServersStatusTest.js
│ ├── schema-validation
│ │ ├── environment-type.sample.json
│ │ └── environment-types.spec.js
│ ├── serviceNameTests.js
│ ├── test-api
│ │ ├── controllers
│ │ │ ├── asgs
│ │ │ │ └── asgControllerTests.js
│ │ │ ├── config
│ │ │ │ └── deploymentMapController.spec.js
│ │ │ ├── instances
│ │ │ │ └── instancesController.spec.js
│ │ │ └── services
│ │ │ │ └── servicesController.spec.js
│ │ ├── dynamicResponseCreator.spec.js
│ │ └── userControllerTest.js
│ ├── test-profile.json
│ └── utils
│ │ ├── fakeLogger.js
│ │ └── sinonHelper.js
└── yarn.lock
├── setup
├── cloudformation
│ ├── .eslintrc.yaml
│ ├── .gitignore
│ ├── EnvironmentManager.template.yaml
│ ├── EnvironmentManagerChildResources.template.json
│ ├── EnvironmentManagerCommonResources.template.js
│ ├── EnvironmentManagerEventAuditListeners
│ │ └── EnvironmentManagerEventsAuditListeners.template.yaml
│ ├── EnvironmentManagerEventPublication
│ │ └── EnvironmentManagerEvents.template.yaml
│ ├── EnvironmentManagerMasterResources.template.js
│ ├── EnvironmentManagerRedis.template.yaml
│ ├── EnvironmentManagerRedisNetwork.template.yaml
│ ├── LambdaFailureAlerts
│ │ └── EnvironmentManagerLambdaFailureAlerts.template.yaml
│ ├── README.md
│ ├── config.yaml
│ ├── lambda
│ │ ├── .eslintignore
│ │ ├── .eslintrc.js
│ │ ├── .jscsrc
│ │ ├── InfraAsgLambdaScale
│ │ │ ├── README.md
│ │ │ ├── index.js
│ │ │ ├── package.json
│ │ │ └── test.js
│ │ ├── InfraEnvironmentManagerAudit
│ │ │ ├── index.js
│ │ │ ├── index.spec.js
│ │ │ ├── package-lock.json
│ │ │ └── package.json
│ │ ├── InfraEnvironmentManagerAuditBackup
│ │ │ ├── AwsAccount.js
│ │ │ ├── DynamoTable.js
│ │ │ ├── DynamoTables.js
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── InfraEnvironmentManagerBackup
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── InfraEnvironmentManagerConfigurationChangeAudit
│ │ │ └── index.js
│ │ ├── InfraEnvironmentManagerOperationsChangeAudit
│ │ │ └── index.js
│ │ ├── InfraEnvironmentManagerScheduler
│ │ │ ├── build.js
│ │ │ ├── environment.js
│ │ │ ├── index.js
│ │ │ ├── local
│ │ │ │ ├── config.sample.json
│ │ │ │ └── index.js
│ │ │ ├── npm-shrinkwrap.json
│ │ │ ├── package.json
│ │ │ ├── presentation
│ │ │ │ ├── reporting.js
│ │ │ │ └── reporting.spec.js
│ │ │ ├── readme.md
│ │ │ ├── scheduler.js
│ │ │ ├── scheduler.tf
│ │ │ └── services
│ │ │ │ ├── aws.js
│ │ │ │ ├── em.js
│ │ │ │ ├── rateLimiter.js
│ │ │ │ └── rateLimiter.spec.js
│ │ └── package.json
│ ├── package.json
│ ├── template.js
│ └── tools
│ │ ├── common.js
│ │ ├── deploy.js
│ │ └── index.js
├── consul-acl
│ ├── consul-deployment-agent.json
│ ├── environment-manager.json
│ └── upstreamr.json
├── data-migration
│ ├── replicate-dynamodb-table
│ │ ├── .eslintrc.yaml
│ │ ├── index.js
│ │ ├── index.spec.js
│ │ ├── package.json
│ │ └── yarn.lock
│ └── touch-dynamodb-table
│ │ ├── .eslintrc.yaml
│ │ ├── index.js
│ │ ├── index.spec.js
│ │ ├── package.json
│ │ └── yarn.lock
├── iam
│ ├── commonInstanceProfile.policy.json
│ ├── roleInfraEnvironmentManager.policy.json
│ └── roleInfraEnvironmentManagerChild.policy.json
├── linux-sample-package.zip
└── terraform
│ └── upstreamCleaner
│ ├── aws_iam_role.tf
│ ├── aws_lambda_function.tf
│ ├── lambda
│ ├── .eslintrc.js
│ ├── build.sh
│ ├── index.js
│ ├── package-lock.json
│ └── package.json
│ └── variables.tf
├── test
├── package.json
├── pages
│ ├── config-page.js
│ ├── config
│ │ └── deploymentmap-page.js
│ ├── home-page.js
│ └── login-page.js
├── specs
│ └── config
│ │ └── deploymentmap-test.spec.js
├── test
│ └── test-ui
│ │ └── screenshots
│ │ └── ERROR_chrome_2018-05-15T12-41-26.078Z.png
└── wdio.conf.js
└── version.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto-detect text files, use LF in repository and working copy
2 | * text=auto eol=lf
3 |
4 | # Binary files. Do not attempt EOL conversion
5 | *.png -text
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '8'
4 |
5 | cache:
6 | directories:
7 | - "${HOME}/.bower"
8 | - "${HOME}/.cache/bower"
9 |
10 | install:
11 | - npm install
12 | - (cd server && exec npm install)
13 | - (cd client && exec npm install)
14 |
15 | before_script:
16 | - npm install -g gulp-cli
17 |
18 | script:
19 | - (cd server && exec npm test)
20 | - (cd client && exec npm test)
21 |
22 | after_success:
23 | - gulp
24 |
25 | addons:
26 | artifacts:
27 | paths:
28 | - $(git ls-files -o test-results | tr "\n" ":")
29 |
30 | deploy:
31 | provider: s3
32 | access_key_id: $ARTIFACTS_KEY
33 | secret_access_key: $ARTIFACTS_SECRET
34 | bucket: $ARTIFACTS_BUCKET
35 | region: $ARTIFACTS_REGION
36 | local_dir: dist
37 | upload-dir: $DIST_DIR
38 | skip_cleanup: true
39 | on:
40 | repo: trainline/environment-manager
41 | all_branches: true
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2015-2016 Trainline.com Ltd
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Environment Manager
2 | Copyright Trainline Limited, 2016
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEPRECATED
2 |
3 | ## This project is no longer maintained
4 |
5 | [](https://travis-ci.org/trainline/environment-manager)
6 |
7 | ### Welcome
8 | Welcome to Environment Manager, an open source platform for automating and managing continuous delivery in AWS.
9 |
10 | ### Requirements
11 | To run Environment Manager, you will need:
12 | - AWS
13 | - NodeJS 6.8.0
14 | - npm
15 |
16 | ### Installation
17 | Please refer to the website for overview and setup instructions:
18 |
19 |
20 |
--------------------------------------------------------------------------------
/client/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "airbnb",
3 | "validateIndentation": 2
4 | }
--------------------------------------------------------------------------------
/client/STYLEGUIDE.md:
--------------------------------------------------------------------------------
1 |
2 | ### All components
3 | - always one component per file
4 |
5 | - direct mapping of component name and filename
6 | ie. ServicesController sits in ServicesController.js
7 |
8 |
9 | ### Naming
10 |
11 | ServicesController.js
12 |
13 | ### Directories
14 |
15 | Multiple words in directories names should be separated by hyphens, ie.: common-modal
16 |
17 |
18 | ### Formatting
19 |
20 | Airbnb
21 | https://github.com/airbnb/javascript
--------------------------------------------------------------------------------
/client/app/common/common.module.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common', [
6 | 'ngRoute',
7 | 'ui.bootstrap'
8 | ]);
9 |
--------------------------------------------------------------------------------
/client/app/common/directives/cronEditor.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/app/common/directives/defaultIfEmptyDirective.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').directive('defaultIfEmpty', function () {
6 | return {
7 | restrict: 'A',
8 | require: 'ngModel',
9 | link: function (scope, elm, attrs, ctrl) {
10 | var defaultValue = attrs.defaultIfEmpty || null;
11 |
12 | ctrl.$parsers.unshift(function (viewValue) {
13 | var result = viewValue !== '' ? viewValue : defaultValue;
14 | return result;
15 | });
16 | }
17 | };
18 | });
19 |
--------------------------------------------------------------------------------
/client/app/common/directives/loadingOverlay.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | angular.module('EnvironmentManager.common')
8 | .component('loadingOverlay', {
9 | restrict: 'E',
10 | bindings: {
11 | },
12 | template: '
',
13 | controllerAs: 'vm',
14 | controller: function (loading) {
15 | var vm = this;
16 | vm.visible = false;
17 | loading.registerLoadingOverlay(vm);
18 | }
19 | });
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/client/app/common/directives/scheduleViewer.html:
--------------------------------------------------------------------------------
1 |
2 |
{{vm.simpleOption}}
3 |
4 |
5 |
6 |
7 | {{ cron.cron }}
8 |
9 |
10 |
in {{ vm.timezone.code }} time
11 |
12 |
13 |
14 |
Time Zone: {{ vm.timezone.readable }}
15 |
Rules:
16 |
17 |
18 | {{ cron.cron }}
19 |
20 |
21 |
Next action: {{ vm.next }}
22 |
23 |
24 |
--------------------------------------------------------------------------------
/client/app/common/services/cacheService.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function () {
4 | angular
5 | .module('EnvironmentManager.common')
6 | .factory('cacheservice', cacheservice);
7 |
8 | cacheservice.$inject = ['$http'];
9 |
10 | function cacheservice($http) {
11 | var url = '/flushcache/';
12 |
13 | return {
14 | flush: flush
15 | };
16 |
17 | /**
18 | * Send 'resetcache' message to target all services in {{environment}}
19 | * @param {String} environment
20 | * @param {Object: {host: String, port: Number, environment: String }} hosts
21 | */
22 | function flush(environment, hosts) {
23 | return $http.post(url + environment, {
24 | hosts: hosts
25 | });
26 | }
27 | }
28 | }());
29 |
--------------------------------------------------------------------------------
/client/app/common/services/comparisons.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').factory('comparisons', function () {
6 | return {
7 | semver: function (a, b) {
8 | var pa = a.split('.');
9 | var pb = b.split('.');
10 | for (var i = 0; i < 3; i++) {
11 | var na = Number(pa[i]);
12 | var nb = Number(pb[i]);
13 | if (na > nb) return 1;
14 | if (nb > na) return -1;
15 | if (!isNaN(na) && isNaN(nb)) return 1;
16 | if (isNaN(na) && !isNaN(nb)) return -1;
17 | }
18 | return 0;
19 | }
20 | };
21 | });
22 |
--------------------------------------------------------------------------------
/client/app/common/services/enumsService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').factory('enums',
6 | function () {
7 | var MILLISECONDS = {
8 | PerHour: 3600000,
9 | PerDay: 86400000
10 | };
11 |
12 | return {
13 | MILLISECONDS: MILLISECONDS
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/client/app/common/services/environmentDeployService.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | angular.module('EnvironmentManager.common').factory('environmentDeploy',
8 | function () {
9 | var deployHandler;
10 |
11 | function registerDeployHandler(handler) {
12 | deployHandler = handler;
13 | }
14 |
15 | function destroyHandler() {
16 | deployHandler = null;
17 | }
18 |
19 | function callDeployHandler() {
20 | deployHandler();
21 | }
22 |
23 | return {
24 | registerDeployHandler: registerDeployHandler,
25 | callDeployHandler: callDeployHandler,
26 | destroyHandler: destroyHandler
27 | }
28 | }
29 | );
30 |
31 |
--------------------------------------------------------------------------------
/client/app/common/services/environmentStorageService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | (function () {
6 | angular
7 | .module('EnvironmentManager.common')
8 | .factory('environmentstorageservice', environmentstorageservice);
9 |
10 | environmentstorageservice.$inject = ['storageservicefactory'];
11 |
12 | function environmentstorageservice(storageservicefactory) {
13 | return storageservicefactory.create('em-selections-environment');
14 | }
15 | }());
16 |
--------------------------------------------------------------------------------
/client/app/common/services/instancesService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').factory('instancesService',
6 | function ($http, $rootScope) {
7 | return {
8 | setMaintenanceMode: function (accountName, instanceId, enable) {
9 | var url = ['api', 'v1', 'instances', instanceId, 'maintenance'].join('/');
10 | return $http.put(url, { enable: enable }).then(function (response) {
11 | return response.data;
12 | }, function (response) {
13 | $rootScope.$broadcast('error', response);
14 | });
15 | }
16 | };
17 | });
18 |
--------------------------------------------------------------------------------
/client/app/common/services/loading.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | angular.module('EnvironmentManager.common').factory('loading',
8 | function () {
9 | var loadingOverlay;
10 |
11 | return {
12 | registerLoadingOverlay: function (overlay) {
13 | loadingOverlay = overlay;
14 | },
15 | lockPage: function (locked) {
16 | loadingOverlay.visible = locked;
17 | }
18 | }
19 |
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/client/app/common/services/localResourceFactoryService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').factory('localResourceFactory',
6 | function ($q) {
7 | function LocalResource(source) {
8 | var dataSource = source;
9 |
10 | this.all = function () {
11 | return $q.when(dataSource);
12 | };
13 | }
14 |
15 | return function (source) {
16 | return new LocalResource(source);
17 | };
18 | });
19 |
--------------------------------------------------------------------------------
/client/app/common/services/localStorageService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | (function () {
6 | angular
7 | .module('EnvironmentManager.common')
8 | .factory('localstorageservice', localstorageservice);
9 |
10 | localstorageservice.$inject = [];
11 |
12 | function localstorageservice() {
13 | var localStorage = window.localStorage;
14 |
15 | return {
16 | get: get,
17 | set: set,
18 | exists: exists
19 | };
20 |
21 | function get(key) {
22 | return localStorage.getItem(key);
23 | }
24 |
25 | function set(key, value) {
26 | return localStorage.setItem(key, value);
27 | }
28 |
29 | function exists(key) {
30 | if (get(key) === null || get(key) === '') return false;
31 | return true;
32 | }
33 | }
34 | }());
35 |
--------------------------------------------------------------------------------
/client/app/common/services/rolesService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common')
6 | .factory('roles', function ($http) {
7 | return {
8 | get: function (accountName, environmentName) {
9 | var url = '/api/v1/target-state/' + environmentName;
10 | return $http.get(url).then(function (response) {
11 | return response.data;
12 | });
13 | }
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/client/app/common/services/serviceDiscovery.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common')
6 | .factory('serviceDiscovery', function ($rootScope, $q, $http) {
7 | function defaultFailure(error) {
8 | $rootScope.$broadcast('error', error);
9 | }
10 |
11 | return {
12 | getASGState: function (environmentName, asgName) {
13 | var path = ['api', 'v1', 'environments', environmentName, 'servers', asgName];
14 | return $http.get(path.join('/')).then(function (response) {
15 | return response.data;
16 | }, defaultFailure);
17 | }
18 | };
19 | });
20 |
--------------------------------------------------------------------------------
/client/app/common/services/taggable.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common')
6 | .factory('taggable', function () {
7 | return function (cls) {
8 | cls.prototype.getTag = function (key) {
9 | var tag = _.find(this.Tags, { Key: key });
10 | if (tag === undefined) {
11 | throw new Error('Can\'t find tag');
12 | }
13 | return tag.Value;
14 | };
15 |
16 | cls.prototype.setTag = function (key, value) {
17 | var tag = this.getTag(key);
18 | if (tag === undefined) {
19 | tag = {
20 | Key: key,
21 | Value: value
22 | };
23 | this.Tags.push(tag);
24 | } else {
25 | tag.Value = value;
26 | }
27 | };
28 | };
29 | });
30 |
--------------------------------------------------------------------------------
/client/app/common/services/targetStateService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.common').factory('targetStateService', function ($rootScope, $q, $http) {
6 | return {
7 | toggleServiceStatus: function (environment, service, slice, enable, serverRole, environmentType) {
8 | var url = '/api/v1/target-state/' + environment + '/' + service + '/toggle-status';
9 |
10 | var data = {
11 | Enable: enable,
12 | Slice: slice,
13 | ServerRole: serverRole,
14 | EnvironmentType: environmentType
15 | };
16 |
17 | return $http.put(url, data)
18 | .then(function (result) {
19 | return result.data;
20 | }, $rootScope.$broadcast.bind($rootScope, 'error'));
21 | }
22 | };
23 | });
24 |
--------------------------------------------------------------------------------
/client/app/common/services/teamStorageService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | (function () {
6 | angular
7 | .module('EnvironmentManager.common')
8 | .factory('teamstorageservice', teamstorageservice);
9 |
10 | teamstorageservice.$inject = ['storageservicefactory'];
11 |
12 | function teamstorageservice(storageservicefactory) {
13 | return storageservicefactory.create('em-selections-team');
14 | }
15 | }());
16 |
--------------------------------------------------------------------------------
/client/app/common/utilities.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | Date.prototype.getDaysBetweenDates = function (date2) {
8 | var diff = this.getTime() - new Date(date2).getTime();
9 | return Math.round(diff / (1000 * 60 * 60 * 24));
10 | };
11 |
12 | Array.prototype.merge = function (targets, comparer, builder) {
13 | return this.map(function (source) {
14 | var target = targets.filter(function (x) { return comparer(source, x); })[0];
15 | return builder(source, target);
16 | });
17 | };
18 |
19 |
--------------------------------------------------------------------------------
/client/app/compare/compare.module.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.compare', [
6 | 'ngRoute',
7 | 'ui.bootstrap',
8 | 'ui.select',
9 | 'EnvironmentManager.common'
10 | ]);
11 |
12 | angular.module('EnvironmentManager.compare').config(function ($routeProvider) {
13 | $routeProvider
14 | .when('/compare', {
15 | templateUrl: '/app/compare/compare.html',
16 | controller: 'CompareController as vm',
17 | menusection: '',
18 | reloadOnSearch: false
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/client/app/compare/diff-viewer/diff-viewer.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/client/app/compare/services/upstreamService.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | angular.module('EnvironmentManager.compare').factory('upstreamService',
8 | function ($http) {
9 |
10 | var baseUrl = '/api/v1/'
11 |
12 | function get() {
13 | return $http.get(baseUrl + 'config/upstreams/');
14 | }
15 |
16 | function getSlice(name, environment) {
17 | return $http.get(baseUrl + 'upstreams/' + name + '/slices/', { params: { environment: environment } });
18 | }
19 |
20 | return {
21 | get: get,
22 | getSlice: getSlice
23 | }
24 | }
25 | );
26 |
27 |
--------------------------------------------------------------------------------
/client/app/configuration/audit/AuditCompareModalController.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | var app = angular.module('EnvironmentManager.configuration').controller('AuditCompareModalController',
8 | function ($scope, $uibModalInstance, audit, arrayItemHashDetector) {
9 | $scope.Audit = audit;
10 | $scope.DiffOptions = arrayItemHashDetector;
11 |
12 | $scope.ok = function () {
13 | $uibModalInstance.dismiss('cancel');
14 | };
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/client/app/configuration/audit/audit-compare-modal.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/client/app/configuration/popovers/multiple-values.html:
--------------------------------------------------------------------------------
1 |
2 | To input multiple values, delimit them with ','
3 |
--------------------------------------------------------------------------------
/client/app/configuration/popovers/notification-settings-paging.html:
--------------------------------------------------------------------------------
1 |
2 | Enter Pager Duty API ID.
3 |
--------------------------------------------------------------------------------
/client/app/configuration/popovers/notification-settings.html:
--------------------------------------------------------------------------------
1 |
2 | Notification settings which will be used for notification alerts of environment / service owned by this team.
3 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/asg/asgSingleInstance.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.environments').component('asgSingleInstance', {
6 | templateUrl: '/app/environments/dialogs/asg/asgSingleInstance.html',
7 | bindings: {
8 | resolve: '<',
9 | close: '&',
10 | dismiss: '&'
11 | },
12 | controllerAs: 'vm',
13 | controller: function () {
14 | var vm = this;
15 | vm.dataLoading = false;
16 | vm.instance = vm.resolve.instance;
17 | vm.showLogLink = function (service) {
18 | return !_.includes(['Ignored'], service.DiffWithTargetState);
19 | };
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/asg/popovers/help-disable-service.html:
--------------------------------------------------------------------------------
1 |
2 | Disabling future installation of a service will prevent any newly created infrastructure from installing it (eg. if you scale up this ASG, new instances will not install a disabled service).
3 |
4 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/asg/popovers/help-service-ignored.html:
--------------------------------------------------------------------------------
1 |
2 | This service is in the target state of this server role, but marked as ignored, so it's not installed. There are no logs for this service installation, because installation wasn't attempted.
3 |
4 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/asg/popovers/help-service-missing.html:
--------------------------------------------------------------------------------
1 |
2 | This service is in the target state of this server role, but not present on this instance. See deployment logs to find out, why it failed.
3 |
4 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/asg/popovers/help-service-unexpected.html:
--------------------------------------------------------------------------------
1 |
2 | This service is present on the instance, but it's not in the target state of this server role.
3 |
4 |
--------------------------------------------------------------------------------
/client/app/environments/dialogs/deployment-dry-run-result.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
The configuration you entered is valid for deployment.
9 |
To deploy a service with this configuration, uncheck the "Dry Run" option.
10 |
11 |
12 |
15 |
--------------------------------------------------------------------------------
/client/app/environments/directives/healthChecks.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | angular.module('EnvironmentManager.environments')
8 | .directive('healthChecks', function ($parse) {
9 | return {
10 | restrict: 'E',
11 | scope: false,
12 | template: ' {{ check.Name }} '
13 | + '- ',
14 | replace: true,
15 | link: function (scope, elm, attrs) {
16 | scope.healthChecks = $parse(attrs.list)(scope);
17 | }
18 | };
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/client/app/environments/directives/serviceDiffWithTargetState.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.environments').component('serviceDiffWithTargetState', {
6 | templateUrl: '/app/environments/directives/serviceDiffWithTargetState.html',
7 | bindings: {
8 | state: '<'
9 | },
10 | controllerAs: 'vm',
11 | controller: function () {
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/client/app/environments/popovers/alert-settings.html:
--------------------------------------------------------------------------------
1 |
2 | Who should get alerts when not explicitly specified in the health check definition.
3 |
--------------------------------------------------------------------------------
/client/app/operations/popovers/instance-deployment-status.html:
--------------------------------------------------------------------------------
1 |
2 | Success - all services on instance deployed successfuly
3 | Failed - at least one service deployment failed
4 | In Progress - at least one of these conditions is true:
5 | - at least one service deployment is in progress
6 | - the deployment hasn't started yet, and less than 60 minutes have passed
7 |
--------------------------------------------------------------------------------
/client/app/operations/upstream/ASGSelectionModalController.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.operations').controller('ASGSelectionModalController',
6 | function ($scope, $uibModal, $uibModalInstance, $q, parameters) {
7 | var vm = this;
8 | vm.asgs = _.uniq(parameters.asgs);
9 |
10 | vm.close = function () {
11 | $uibModalInstance.dismiss();
12 | };
13 |
14 | vm.selectASG = function (asg) {
15 | $uibModalInstance.close(asg);
16 | };
17 | });
18 |
--------------------------------------------------------------------------------
/client/app/operations/upstream/select-asg-modal.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/client/app/settings/settings.module.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | angular.module('EnvironmentManager.settings', []);
6 |
--------------------------------------------------------------------------------
/client/app/settings/user-settings-modal.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
15 |
16 |
--------------------------------------------------------------------------------
/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/css/bootstrap-3.3.5/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/client/assets/css/bootstrap-3.3.5/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition')
3 | require('../../js/alert')
4 | require('../../js/button')
5 | require('../../js/carousel')
6 | require('../../js/collapse')
7 | require('../../js/dropdown')
8 | require('../../js/modal')
9 | require('../../js/tooltip')
10 | require('../../js/popover')
11 | require('../../js/scrollspy')
12 | require('../../js/tab')
13 | require('../../js/affix')
--------------------------------------------------------------------------------
/client/assets/images/activity.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/images/activity.gif
--------------------------------------------------------------------------------
/client/assets/images/clippy.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/assets/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/images/favicon-16x16.png
--------------------------------------------------------------------------------
/client/assets/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/images/favicon-32x32.png
--------------------------------------------------------------------------------
/client/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/images/favicon.ico
--------------------------------------------------------------------------------
/client/assets/images/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/assets/images/logo.jpg
--------------------------------------------------------------------------------
/client/assets/lib/thenBy.min.js:
--------------------------------------------------------------------------------
1 | /*** Copyright 2013 Teun Duynstee Licensed under the Apache License, Version 2.0 ***/
2 | firstBy = function () { function n(n, t) { if ("function" != typeof n) { var r = n; n = function (n) { return n[r]?n[r]:"" } } if (1 === n.length) { var u = n; n = function (n, t) { return u(n) < u(t)?-1:u(n) > u(t)?1:0 } } return -1 === t?function (t, r) { return -n(t, r) }:n } function t(t, u) { return t = n(t, u), t.thenBy = r, t } function r(r, u) { var f = this; return r = n(r, u), t(function (n, t) { return f(n, t) || r(n, t) }) } return t }();
--------------------------------------------------------------------------------
/client/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "environments-manager",
3 | "version": "3.0.0",
4 | "dependencies": {
5 | "moment": "~2.10.6",
6 | "angular": "~1.6.1",
7 | "jsondiffpatch": "^0.1.43",
8 | "lodash": "^4.13.1",
9 | "prettycron": "^0.10.0",
10 | "angular-ui-tree": "^2.16.0",
11 | "spin": "^1.1.6",
12 | "angular-ui-grid": "ui-grid#^3.2.1",
13 | "select": "^1.0.6",
14 | "later": "^1.2.0",
15 | "angular-route": "^1.6.1",
16 | "ngclipboard": "^1.1.1",
17 | "moment-timezone": "^0.5.11",
18 | "angular-loading-bar": "^0.9.0",
19 | "angular-smart-table": "^2.1.8",
20 | "Tourist.js": "tourist#^0.1.2",
21 | "backbone": "^1.3.3",
22 | "jquery": "^3.2.1",
23 | "highcharts-ng": "^1.1.0",
24 | "highcharts": "^6.0.1"
25 | },
26 | "devDependencies": {
27 | "angular-mocks": "~1.6.1"
28 | },
29 | "resolutions": {
30 | "angular": "~1.6.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/client/docs/css/typography.css:
--------------------------------------------------------------------------------
1 | /* Google Font's Droid Sans */
2 | @font-face {
3 | font-family: 'Droid Sans';
4 | font-style: normal;
5 | font-weight: 400;
6 | src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf') format('truetype');
7 | }
8 | /* Google Font's Droid Sans Bold */
9 | @font-face {
10 | font-family: 'Droid Sans';
11 | font-style: normal;
12 | font-weight: 700;
13 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf') format('truetype');
14 | }
15 |
--------------------------------------------------------------------------------
/client/docs/fonts/DroidSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/fonts/DroidSans-Bold.ttf
--------------------------------------------------------------------------------
/client/docs/fonts/DroidSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/fonts/DroidSans.ttf
--------------------------------------------------------------------------------
/client/docs/images/collapse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/collapse.gif
--------------------------------------------------------------------------------
/client/docs/images/expand.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/expand.gif
--------------------------------------------------------------------------------
/client/docs/images/explorer_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/explorer_icons.png
--------------------------------------------------------------------------------
/client/docs/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/favicon-16x16.png
--------------------------------------------------------------------------------
/client/docs/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/favicon-32x32.png
--------------------------------------------------------------------------------
/client/docs/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/favicon.ico
--------------------------------------------------------------------------------
/client/docs/images/logo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/logo_small.png
--------------------------------------------------------------------------------
/client/docs/images/pet_store_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/pet_store_api.png
--------------------------------------------------------------------------------
/client/docs/images/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/throbber.gif
--------------------------------------------------------------------------------
/client/docs/images/wordnik_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/client/docs/images/wordnik_api.png
--------------------------------------------------------------------------------
/client/docs/lib/jquery.slideto.min.js:
--------------------------------------------------------------------------------
1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery);
2 |
--------------------------------------------------------------------------------
/client/docs/lib/jquery.wiggle.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | jQuery Wiggle
3 | Author: WonderGroup, Jordan Thomas
4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html
5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License)
6 | */
7 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('
').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);}
8 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});};
--------------------------------------------------------------------------------
/client/gulp/eslint.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var eslint = require('gulp-eslint');
3 |
4 | gulp.task('lint', function () {
5 | return gulp.src(['./app/**/*.js', '!node_modules/**'])
6 | .pipe(eslint())
7 | .pipe(eslint.format())
8 | .pipe(eslint.failAfterError());
9 | });
10 |
11 |
12 | gulp.task('lint-fix', function () {
13 | return gulp.src(['./app/**/*.js', '!node_modules/**'])
14 | .pipe(eslint({
15 | fix: true
16 | }))
17 | .pipe(eslint.format())
18 | .pipe(eslint.failAfterError())
19 | .pipe(gulp.dest('./app'));
20 | });
21 |
--------------------------------------------------------------------------------
/client/gulp/scripts.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 |
5 | 'use strict';
6 |
7 | var gulp = require('gulp');
8 |
9 | var browserSync = require('browser-sync');
10 |
11 | var $ = require('gulp-load-plugins')();
12 |
13 |
14 | gulp.task('scripts-reload', function () {
15 | return buildScripts()
16 | .pipe(browserSync.stream());
17 | });
18 |
19 | gulp.task('scripts', function () {
20 | return buildScripts();
21 | });
22 |
23 | function buildScripts() {
24 | return gulp.src('app/**/*.js')
25 | .pipe($.eslint())
26 | .pipe($.eslint.format())
27 | .pipe($.size());
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/client/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict';
3 |
4 | let fs = require('fs');
5 | let gulp = require('gulp');
6 | let zip = require('gulp-zip');
7 |
8 | /**
9 | * This will load all js files in the gulp directory
10 | * in order to load all gulp tasks
11 | */
12 | fs.readdirSync('./gulp').filter(function(file) {
13 | return (/\.js$/i).test(file);
14 | }).map(function(file) {
15 | require('./gulp/' + file);
16 | });
17 |
18 | /**
19 | * Default task clean temporaries directories and launch the
20 | * main optimization build task
21 | */
22 | gulp.task('default', ['clean'], function () {
23 | gulp.start('serve');
24 | });
25 |
--------------------------------------------------------------------------------
/client/protractor.conf.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict';
3 |
4 | // An example configuration file.
5 | exports.config = {
6 | // The address of a running selenium server.
7 | //seleniumAddress: 'http://localhost:4444/wd/hub',
8 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json
9 |
10 | // Capabilities to be passed to the webdriver instance.
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 |
15 | baseUrl: 'http://localhost:3001',
16 |
17 | // Spec patterns are relative to the current working directory when
18 | // protractor is called.
19 | specs: ['./test/e2e/**/*.js'],
20 |
21 | // Options to be passed to Jasmine-node.
22 | jasmineNodeOpts: {
23 | showColors: true,
24 | defaultTimeoutInterval: 30000
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/client/test/lib/ngAnimateMock.js:
--------------------------------------------------------------------------------
1 | require('./angular-mocks');
2 | module.exports = 'ngAnimateMock';
3 |
--------------------------------------------------------------------------------
/client/test/lib/ngMock.js:
--------------------------------------------------------------------------------
1 | require('./angular-mocks');
2 | module.exports = 'ngMock';
3 |
--------------------------------------------------------------------------------
/client/test/lib/ngMockE2E.js:
--------------------------------------------------------------------------------
1 | require('./angular-mocks');
2 | module.exports = 'ngMockE2E';
3 |
--------------------------------------------------------------------------------
/em2/README.md:
--------------------------------------------------------------------------------
1 | # Environment Manager (Serverless)
2 |
3 | ## Deployments..
4 |
5 | - Install serverless
6 |
7 | ``` npm install -g serverless ```
8 |
9 | - Set AWS Credentials in Environment Variables
10 | - Open prompt at service level. E.g..
11 |
12 | ``` cd config/accounts ```
13 |
14 | - Install dependencies
15 |
16 | ``` npm install ```
17 |
18 | - Deploy
19 |
20 | ``` serverless deploy --region eu-west-1 --stage uat --bucket my-uat-packages-bucket ```
--------------------------------------------------------------------------------
/em2/config/accounts/index.js:
--------------------------------------------------------------------------------
1 | let rl = require('roast-lambda');
2 | let _ = require('lodash');
3 |
4 | let lambdas = require('./src/lambdas');
5 | let dynamo = require('./src/services/dynamo');
6 |
7 | function inject(fn) {
8 | return (args) => {
9 | args.dynamo = dynamo.createClient(args.AWS, args.context.awsRegion, args.context.env.STAGE);
10 | return fn(args);
11 | };
12 | }
13 |
14 | _.forOwn(lambdas, (lambda, name) => {
15 | lambda.handler = inject(lambda.handler);
16 | exports[name] = rl.init(lambda);
17 | });
--------------------------------------------------------------------------------
/em2/config/accounts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "em-get-accounts",
3 | "version": "0.0.1",
4 | "description": "Gets all AWS Accounts",
5 | "main": "index.js",
6 | "scripts": {
7 | "deploy": "serverless deploy --region eu-west-1"
8 | },
9 | "author": "Trainline",
10 | "dependencies": {
11 | "lodash": "^4.17.4",
12 | "roast-lambda": "0.x.x"
13 | },
14 | "files": [
15 | "index.js",
16 | "package.json",
17 | "src/**",
18 | "node_modules/**"
19 | ],
20 | "devDependencies": {
21 | "co": "^4.6.0",
22 | "request": "^2.81.0",
23 | "request-promise": "^4.2.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/em2/config/accounts/readme.md:
--------------------------------------------------------------------------------
1 | # Config / Accounts Lambda
2 |
3 | Gets and sets accounts
--------------------------------------------------------------------------------
/em2/deploy/account/aws_default_network_acl.tf:
--------------------------------------------------------------------------------
1 | resource "aws_default_network_acl" "default" {
2 | default_network_acl_id = "${aws_vpc.main.default_network_acl_id}"
3 |
4 | ingress {
5 | protocol = -1
6 | rule_no = 100
7 | action = "allow"
8 | cidr_block = "0.0.0.0/0"
9 | from_port = 0
10 | to_port = 0
11 | }
12 |
13 | egress {
14 | protocol = -1
15 | rule_no = 100
16 | action = "allow"
17 | cidr_block = "0.0.0.0/0"
18 | from_port = 0
19 | to_port = 0
20 | }
21 |
22 | tags {
23 | Name = "NACL"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_default_route_table.tf:
--------------------------------------------------------------------------------
1 | resource "aws_default_route_table" "private" {
2 | default_route_table_id = "${aws_vpc.main.default_route_table_id}"
3 |
4 | route {
5 | cidr_block = "0.0.0.0/0"
6 | nat_gateway_id = "${aws_nat_gateway.gw.id}"
7 | }
8 |
9 | tags {
10 | Name = "Private Subnets"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_default_security_group.tf:
--------------------------------------------------------------------------------
1 | resource "aws_default_security_group" "default" {
2 | vpc_id = "${aws_vpc.main.id}"
3 |
4 | ingress {
5 | from_port = 0
6 | to_port = 0
7 | protocol = "-1"
8 | cidr_blocks = ["172.27.224.0/20", "172.31.0.0/16"]
9 | }
10 |
11 | egress {
12 | from_port = 0
13 | to_port = 0
14 | protocol = "-1"
15 | cidr_blocks = ["0.0.0.0/0"]
16 | }
17 |
18 | tags {
19 | Name = "sg-default"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_internet_gateway.tf:
--------------------------------------------------------------------------------
1 | resource "aws_internet_gateway" "gw" {
2 | vpc_id = "${aws_vpc.main.id}"
3 |
4 | tags {
5 | Name = "internet-gateway"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_main_route_table_association.tf:
--------------------------------------------------------------------------------
1 | resource "aws_main_route_table_association" "a" {
2 | vpc_id = "${aws_vpc.main.id}"
3 | route_table_id = "${aws_default_route_table.private.id}"
4 | }
5 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_nat_gateway.tf:
--------------------------------------------------------------------------------
1 | resource "aws_nat_gateway" "gw" {
2 | allocation_id = "${aws_eip.nat.id}"
3 | subnet_id = "${aws_subnet.public_a.id}"
4 | depends_on = ["aws_internet_gateway.gw"]
5 | }
6 |
7 | resource "aws_eip" "nat" {
8 | vpc = true
9 | }
10 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_route_table.tf:
--------------------------------------------------------------------------------
1 | resource "aws_route_table" "public" {
2 | vpc_id = "${aws_vpc.main.id}"
3 |
4 | route {
5 | cidr_block = "0.0.0.0/0"
6 | gateway_id = "${aws_internet_gateway.gw.id}"
7 | }
8 |
9 | tags {
10 | Name = "Public Subnets"
11 | }
12 | }
13 |
14 | resource "aws_route_table" "elb" {
15 | vpc_id = "${aws_vpc.main.id}"
16 |
17 | route {
18 | cidr_block = "0.0.0.0/0"
19 | gateway_id = "${aws_internet_gateway.gw.id}"
20 | }
21 |
22 | tags {
23 | Name = "ELB Subnets"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/em2/deploy/account/aws_vpc.tf:
--------------------------------------------------------------------------------
1 | resource "aws_vpc" "main" {
2 | cidr_block = "${var.vpc_cidr}"
3 |
4 | tags {
5 | Name = "${var.vpc_name}"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/em2/deploy/account/em_provider.tf:
--------------------------------------------------------------------------------
1 | # AWS
2 | provider "aws" {}
3 |
4 | data "aws_region" "current" {
5 | current = true
6 | }
7 |
8 | # Use this data source to get the access to the effective
9 | # Account ID, User ID, and ARN in which Terraform is authorized.
10 | data "aws_caller_identity" "current" {}
11 |
--------------------------------------------------------------------------------
/em2/deploy/account/outputs.tf:
--------------------------------------------------------------------------------
1 | output "Subnet ELB A" {
2 | value = "{${aws_subnet.elb_a.id}}"
3 | }
4 |
5 | output "Subnet ELB B" {
6 | value = "{${aws_subnet.elb_b.id}}"
7 | }
8 |
9 | output "Subnet ELB C" {
10 | value = "{${aws_subnet.elb_c.id}}"
11 | }
12 |
13 | output "Subnet Public A" {
14 | value = "{${aws_subnet.public_a.id}}"
15 | }
16 |
17 | output "Subnet Public B" {
18 | value = "{${aws_subnet.public_b.id}}"
19 | }
20 |
21 | output "Subnet Public C" {
22 | value = "{${aws_subnet.public_c.id}}"
23 | }
24 |
25 | output "Subnet Private A" {
26 | value = "{${aws_subnet.private_a.id}}"
27 | }
28 |
29 | output "Subnet Private B" {
30 | value = "{${aws_subnet.private_b.id}}"
31 | }
32 |
33 | output "Subnet Private C" {
34 | value = "{${aws_subnet.private_c.id}}"
35 | }
36 |
--------------------------------------------------------------------------------
/em2/deploy/account/remote_state.tf:
--------------------------------------------------------------------------------
1 | # Write the remote state
2 | terraform {
3 | backend "s3" {
4 | bucket = "terraform-em-remote-state"
5 | key = "account"
6 | region = "eu-west-1"
7 | }
8 | }
9 |
10 | # Use the remote state
11 | data "terraform_remote_state" "remote_state" {
12 | backend = "s3"
13 |
14 | config {
15 | bucket = "terraform-em-remote-state"
16 | key = "account"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/em2/deploy/ami/ubuntu_1604/userdata_ubuntu_1604.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #init
3 | apt-get update
4 | apt-get install awscli -y
5 |
6 | #fetch init script from s3
7 | aws s3api get-object --bucket em-testing-init --key init_ubuntu_1604.sh ./init_ubuntu_1604.sh
8 |
9 | #execute init script
10 | chmod 700 ./init_ubuntu_1604.sh
11 | ./init_ubuntu_1604.sh
12 |
--------------------------------------------------------------------------------
/em2/deploy/consul/outputs.tf:
--------------------------------------------------------------------------------
1 | output "server_address" {
2 | value = "${aws_instance.server.0.public_dns}"
3 | }
4 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/debian_consul.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=consul agent
3 | Wants=basic.target
4 | After=basic.target network.target
5 |
6 | [Service]
7 | EnvironmentFile=-/etc/default/consul
8 | Restart=on-failure
9 | ExecStart=/usr/local/bin/consul agent $CONSUL_FLAGS -config-dir=/etc/consul.d
10 | ExecReload=/bin/kill -HUP $MAINPID
11 | KillMode=process
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/debian_upstart.conf:
--------------------------------------------------------------------------------
1 | description "Consul agent"
2 |
3 | start on started networking
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 | # This is to avoid Upstart re-spawning the process upon `consul leave`
8 | normal exit 0 INT
9 |
10 | script
11 | if [ -f "/etc/service/consul" ]; then
12 | . /etc/service/consul
13 | fi
14 |
15 | # Get the local IP
16 | BIND=`ifconfig eth0 | grep "inet addr" | awk '{ print substr($2,6) }'`
17 |
18 | exec /usr/local/bin/consul agent \
19 | -config-dir="/etc/consul.d" \
20 | -bind=$BIND \
21 | ${CONSUL_FLAGS} \
22 | >>/var/log/consul.log 2>&1
23 | end script
24 |
25 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/iptables.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8300 -j ACCEPT
5 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8301 -j ACCEPT
6 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8302 -j ACCEPT
7 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8400 -j ACCEPT
8 |
9 | if [ -d /etc/sysconfig ]; then
10 | sudo iptables-save | sudo tee /etc/sysconfig/iptables
11 | else
12 | sudo iptables-save | sudo tee /etc/iptables.rules
13 | fi
14 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/rhel_consul.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=consul agent
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | EnvironmentFile=-/etc/sysconfig/consul
8 | Restart=on-failure
9 | ExecStart=/usr/local/bin/consul agent $CONSUL_FLAGS -config-dir=/etc/consul.d
10 | ExecReload=/bin/kill -HUP $MAINPID
11 | KillMode=process
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/rhel_upstart.conf:
--------------------------------------------------------------------------------
1 | description "Consul agent"
2 |
3 | start on started network
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 | # This is to avoid Upstart re-spawning the process upon `consul leave`
8 | normal exit 0 INT
9 |
10 | script
11 | if [ -f "/etc/service/consul" ]; then
12 | . /etc/service/consul
13 | fi
14 |
15 | # Make sure to use all our CPUs, because Consul can block a scheduler thread
16 | export GOMAXPROCS=`nproc`
17 |
18 | # Get the public IP
19 | BIND=`ifconfig eth0 | grep "inet addr" | awk '{ print substr($2,6) }'`
20 |
21 | exec /usr/local/bin/consul agent \
22 | -config-dir="/etc/consul.d" \
23 | -bind=$BIND \
24 | ${CONSUL_FLAGS} \
25 | >>/var/log/consul.log 2>&1
26 | end script
27 |
--------------------------------------------------------------------------------
/em2/deploy/consul/scripts/service.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | echo "Starting Consul..."
5 | if [ -x "$(command -v systemctl)" ]; then
6 | echo "using systemctl"
7 | sudo systemctl enable consul.service
8 | sudo systemctl start consul
9 | else
10 | echo "using upstart"
11 | sudo start consul
12 | fi
13 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/em-provider.tf:
--------------------------------------------------------------------------------
1 | # AWS
2 | provider "aws" {}
3 |
4 | data "aws_region" "current" {
5 | current = true
6 | }
7 |
8 | # Use this data source to get the access to the effective
9 | # Account ID, User ID, and ARN in which Terraform is authorized.
10 | data "aws_caller_identity" "current" {}
11 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/outputs.tf:
--------------------------------------------------------------------------------
1 | # output "server_address" {
2 | # value = "${aws_instance.server.0.public_dns}"
3 | # }
4 |
5 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/debian_consul.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=consul agent
3 | Wants=basic.target
4 | After=basic.target network.target
5 |
6 | [Service]
7 | EnvironmentFile=-/etc/default/consul
8 | Restart=on-failure
9 | ExecStart=/usr/local/bin/consul agent $CONSUL_FLAGS -config-dir=/etc/consul.d
10 | ExecReload=/bin/kill -HUP $MAINPID
11 | KillMode=process
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/debian_upstart.conf:
--------------------------------------------------------------------------------
1 | description "Consul agent"
2 |
3 | start on started networking
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 | # This is to avoid Upstart re-spawning the process upon `consul leave`
8 | normal exit 0 INT
9 |
10 | script
11 | if [ -f "/etc/service/consul" ]; then
12 | . /etc/service/consul
13 | fi
14 |
15 | # Get the local IP
16 | BIND=`ifconfig eth0 | grep "inet addr" | awk '{ print substr($2,6) }'`
17 |
18 | exec /usr/local/bin/consul agent \
19 | -config-dir="/etc/consul.d" \
20 | -bind=$BIND \
21 | ${CONSUL_FLAGS} \
22 | >>/var/log/consul.log 2>&1
23 | end script
24 |
25 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/iptables.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8300 -j ACCEPT
5 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8301 -j ACCEPT
6 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8302 -j ACCEPT
7 | sudo iptables -I INPUT -s 0/0 -p tcp --dport 8400 -j ACCEPT
8 |
9 | if [ -d /etc/sysconfig ]; then
10 | sudo iptables-save | sudo tee /etc/sysconfig/iptables
11 | else
12 | sudo iptables-save | sudo tee /etc/iptables.rules
13 | fi
14 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/rhel_consul.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=consul agent
3 | Requires=network-online.target
4 | After=network-online.target
5 |
6 | [Service]
7 | EnvironmentFile=-/etc/sysconfig/consul
8 | Restart=on-failure
9 | ExecStart=/usr/local/bin/consul agent $CONSUL_FLAGS -config-dir=/etc/consul.d
10 | ExecReload=/bin/kill -HUP $MAINPID
11 | KillMode=process
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/rhel_upstart.conf:
--------------------------------------------------------------------------------
1 | description "Consul agent"
2 |
3 | start on started network
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 | # This is to avoid Upstart re-spawning the process upon `consul leave`
8 | normal exit 0 INT
9 |
10 | script
11 | if [ -f "/etc/service/consul" ]; then
12 | . /etc/service/consul
13 | fi
14 |
15 | # Make sure to use all our CPUs, because Consul can block a scheduler thread
16 | export GOMAXPROCS=`nproc`
17 |
18 | # Get the public IP
19 | BIND=`ifconfig eth0 | grep "inet addr" | awk '{ print substr($2,6) }'`
20 |
21 | exec /usr/local/bin/consul agent \
22 | -config-dir="/etc/consul.d" \
23 | -bind=$BIND \
24 | ${CONSUL_FLAGS} \
25 | >>/var/log/consul.log 2>&1
26 | end script
27 |
--------------------------------------------------------------------------------
/em2/deploy/em-child/scripts/service.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | echo "Starting Consul..."
5 | if [ -x "$(command -v systemctl)" ]; then
6 | echo "using systemctl"
7 | sudo systemctl enable consul.service
8 | sudo systemctl start consul
9 | else
10 | echo "using upstart"
11 | sudo start consul
12 | fi
13 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/aws_ami.tf:
--------------------------------------------------------------------------------
1 | data "aws_ami" "ubuntu" {
2 | most_recent = true
3 |
4 | filter {
5 | name = "image-id"
6 | values = ["ami-a8d2d7ce"]
7 | }
8 |
9 | filter {
10 | name = "virtualization-type"
11 | values = ["hvm"]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/aws_cloudwatch_event_rules.tf:
--------------------------------------------------------------------------------
1 | resource "aws_cloudwatch_event_rule" "every_five_minutes" {
2 | name = "every-5-minutes"
3 | description = "5 minute repeating cloudwatch event"
4 | schedule_expression = "rate(5 minutes)"
5 | }
6 |
7 | resource "aws_cloudwatch_event_target" "scheduler_cloudwatch_scheduled_trigger" {
8 | rule = "${aws_cloudwatch_event_rule.every_five_minutes.name}"
9 | target_id = "em-scheduler-trigger"
10 | arn = "${aws_lambda_function.scheduler.arn}"
11 | }
12 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/aws_elasticache_cluster.tf:
--------------------------------------------------------------------------------
1 | resource "aws_elasticache_cluster" "cache-cluster" {
2 | cluster_id = "${var.stack}"
3 | node_type = "cache.t2.micro"
4 |
5 | subnet_group_name = "${var.redis_subnet_group}"
6 | engine = "redis"
7 | num_cache_nodes = 1
8 | port = 11211
9 | security_group_ids = ["${var.default_sg}"]
10 | }
11 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/aws_iam_instance_profile.tf:
--------------------------------------------------------------------------------
1 | resource "aws_iam_instance_profile" "app" {
2 | name = "${var.stack}-app"
3 | role = "${aws_iam_role.app.name}"
4 | }
5 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/aws_sns_topic.tf:
--------------------------------------------------------------------------------
1 | resource "aws_sns_topic" "alert_sns_topic" {
2 | name = "${var.stack}-alert-sns-topic"
3 | }
4 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/em-provider.tf:
--------------------------------------------------------------------------------
1 | # AWS
2 | provider "aws" {}
3 |
4 | data "aws_region" "current" {
5 | current = true
6 | }
7 |
8 | # Use this data source to get the access to the effective
9 | # Account ID, User ID, and ARN in which Terraform is authorized.
10 | data "aws_caller_identity" "current" {}
11 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/em-terraform-remote-state.tf:
--------------------------------------------------------------------------------
1 | # Write the remote state
2 | terraform {
3 | backend "s3" {
4 | bucket = "newco-remote-state-master"
5 | key = "demo"
6 | region = "eu-west-1"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/em-variables.tf:
--------------------------------------------------------------------------------
1 | # App
2 |
3 | variable "stack" {}
4 |
5 | variable "ec2_key_pair" {}
6 |
7 | # Buckets
8 |
9 | variable "bucket" {}
10 |
11 | variable "secure_bucket" {}
12 |
13 | variable "init_script_bucket" {}
14 |
15 | # Scheduler
16 |
17 | variable scheduler_package {}
18 |
19 | # Redis
20 |
21 | variable "redis_subnet_group" {}
22 |
23 | # Security Groups
24 |
25 | variable "default_sg" {}
26 |
27 | variable "app_sg_cidr_inbound" {
28 | type = "list"
29 | }
30 |
31 | variable "app_sg_cidr_outbound" {
32 | type = "list"
33 | }
34 |
35 | # Account
36 |
37 | variable "vpc_id" {}
38 |
39 | variable "subnet_ids" {
40 | type = "map"
41 | }
42 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/environment-manager.env:
--------------------------------------------------------------------------------
1 | EM_AWS_REGION=eu-west-1
2 | EM_AWS_S3_BUCKET=em-daveandjake-config
3 | EM_AWS_S3_KEY=config.json
4 | AWS_REGION=eu-west-1
5 | EM_PACKAGES_BUCKET=em-daveandjake-packages
6 | EM_PACKAGES_KEY_PREFIX=packages
7 | IS_PRODUCTION=true
8 | EM_REDIS_ADDRESS=em-cache-cluster.qcyyv8.0001.euw1.cache.amazonaws.com
9 | EM_REDIS_PORT=11211
10 | EM_REDIS_CRYPTO_KEY="abcdefg"
11 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | < fs.mkdir(outDir));
15 | yield zipFiles(__dirname, config.files, destination);
16 |
17 | console.log(destination);
18 | });
19 |
20 | function zipFiles(path, files, destination) {
21 | let archive = archiver(destination);
22 | archive.pipe(fs.createWriteStream(destination));
23 | files.forEach(file => archive.glob(file, { cwd: path }));
24 | return archive.finalize();
25 | }
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/InfraEnvironmentManagerScheduler/local/config.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "em": {
3 | "host": "https://environment-manager-domain-name",
4 | "credentials": {
5 | "username": "username",
6 | "password": "password"
7 | }
8 | },
9 | "limitToEnvironment": "xxx",
10 | "whatIf": true,
11 | "listSkippedInstances": true,
12 | "ignoreASGInstances": false,
13 | "errorOnFailure": true
14 | }
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/InfraEnvironmentManagerScheduler/local/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict'
3 |
4 | let config = require('./config.json');
5 | let emFactory = require('../services/em');
6 | let schedulerFactory = require('../scheduler');
7 |
8 | let awsConfig = { region: 'eu-west-1' };
9 | let em = emFactory.create(config.em);
10 |
11 | let context = { awsAccountId: 123456789, awsRegion: 'eu-west-1', env: { CHILD_ACCOUNT_ROLE_NAME: 'enterRoleName' } };
12 | let scheduler = schedulerFactory.create(config, em, require('aws-sdk'), context);
13 |
14 | let write = result => console.log(JSON.stringify(result, null, 2));
15 |
16 | scheduler.doScheduling()
17 | .then(write).catch(write);
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lambda",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha --recursive ./test --EM_PROFILE test/test-profile.json",
8 | "test-watch": "mocha --watch --recursive ./test --EM_PROFILE test/test-profile.json"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "aws-sdk": "^2.26.0",
14 | "eslint": "^3.17.1",
15 | "eslint-config-airbnb-base": "^11.1.1",
16 | "eslint-plugin-import": "^2.2.0",
17 | "mocha": "^3.2.0",
18 | "rewire": "^2.5.2",
19 | "sinon": "^1.17.7"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/scheduler/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let archiver = require('archiver-promise');
4 | let fs = require('fs-extra');
5 | let co = require('co');
6 |
7 | let config = require('./package.json');
8 |
9 | co(function* () {
10 | let { name, version } = config;
11 | let outDir = 'out';
12 | let destination = `${outDir}/${name}-${version}.zip`;
13 |
14 | yield fs.remove(outDir).then(() => fs.mkdir(outDir));
15 | yield zipFiles(__dirname, config.files, destination);
16 |
17 | console.log(destination);
18 | });
19 |
20 | function zipFiles(path, files, destination) {
21 | let archive = archiver(destination);
22 | archive.pipe(fs.createWriteStream(destination));
23 | files.forEach(file => archive.glob(file, { cwd: path }));
24 | return archive.finalize();
25 | }
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/scheduler/local/config.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "em": {
3 | "host": "https://environment-manager-domain-name",
4 | "credentials": {
5 | "username": "username",
6 | "password": "password"
7 | }
8 | },
9 | "limitToEnvironment": "xxx",
10 | "whatIf": true,
11 | "listSkippedInstances": true,
12 | "ignoreASGInstances": false,
13 | "errorOnFailure": true
14 | }
--------------------------------------------------------------------------------
/em2/deploy/em-master/lambda/scheduler/local/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict'
3 |
4 | let config = require('./config.json');
5 | let emFactory = require('../services/em');
6 | let schedulerFactory = require('../scheduler');
7 |
8 | let awsConfig = { region: 'eu-west-1' };
9 | let em = emFactory.create(config.em);
10 |
11 | let context = { awsAccountId: 123456789, awsRegion: 'eu-west-1', env: { CHILD_ACCOUNT_ROLE_NAME: 'enterRoleName' } };
12 | let scheduler = schedulerFactory.create(config, em, require('aws-sdk'), context);
13 |
14 | let write = result => console.log(JSON.stringify(result, null, 2));
15 |
16 | scheduler.doScheduling()
17 | .then(write).catch(write);
--------------------------------------------------------------------------------
/em2/deploy/scripts/consul_server_install.sh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/em2/deploy/scripts/consul_server_install.sh
--------------------------------------------------------------------------------
/em2/gateway/session/index.js:
--------------------------------------------------------------------------------
1 | let rl = require('roast-lambda');
2 | let _ = require('lodash');
3 |
4 | let lambdas = require('./src/lambdas');
5 |
6 | function inject(fn) {
7 | return (args) => {
8 | return fn(args);
9 | };
10 | }
11 |
12 | _.forOwn(lambdas, (lambda, name) => {
13 | lambda.handler = inject(lambda.handler);
14 | exports[name] = rl.init(lambda);
15 | });
--------------------------------------------------------------------------------
/em2/gateway/session/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "auth-lambda",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "roast-lambda": "^0.1.6"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/em2/gateway/session/src/lambdas.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let sessionService = require('./services/session-service');
4 |
5 | exports.authenticate = {
6 | handler: ({ event, context }) => {
7 | let res = sessionService.authenticate({ user })
8 | .then(jsonResponse);
9 | }
10 | }
11 |
12 | exports.getSession = {
13 | handler: ({ event, context }) => {
14 | return tokenService.createToken(user)
15 | .then(jsonResponse);
16 | }
17 | }
18 |
19 | exports.createToken = {
20 | handler: ({ event, context }) => {
21 | return tokenService.createSession()
22 | .then(jsonResponse);
23 | }
24 | }
25 |
26 | exports.storeToken = {
27 | handler: ({ event, context }) => {
28 | return tokenService.storeSession()
29 | .then(jsonResponse);
30 | }
31 | }
32 |
33 | function jsonResponse(data) {
34 | return {
35 | statusCode: 200,
36 | body: data ? JSON.stringify(data) : undefined
37 | };
38 | }
--------------------------------------------------------------------------------
/server/.eslintignore:
--------------------------------------------------------------------------------
1 | /acceptance-tests/**/*.*
2 | /build/**/*.*
3 | /deployment/**/*.*
4 | /node_modules/**/*.*
5 | /scripts/**/*.*
6 | /src/test/**/*.*
7 |
--------------------------------------------------------------------------------
/server/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "airbnb",
3 | "validateIndentation": 2
4 | }
--------------------------------------------------------------------------------
/server/api/api-utils/dateUtil.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | function beginningOfToday() {
6 | let today = new Date();
7 | today.setHours(0, 0, 0, 0);
8 | return toDynamoFormat(today);
9 | }
10 |
11 | function toDynamoFormat(date) {
12 | return date.toISOString();
13 | }
14 |
15 | module.exports = { beginningOfToday, toDynamoFormat };
16 |
--------------------------------------------------------------------------------
/server/api/api-utils/ifNotFound.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let { hasValue, when } = require('../../modules/functional');
4 |
5 | let ifNotFound = when.bind(null, hasValue, data => res => res.json(data));
6 |
7 | let notFoundMessage = resourceType =>
8 | () => res => res.status(404).json({ error: `The ${resourceType} was not found` });
9 |
10 | module.exports = {
11 | ifNotFound,
12 | notFoundMessage
13 | };
14 |
--------------------------------------------------------------------------------
/server/api/api-utils/logicalTableName.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const logicalTableNames = {
4 | accounts: 'InfraConfigAccounts',
5 | clusters: 'InfraConfigClusters',
6 | deploymentmaps: 'ConfigDeploymentMaps',
7 | environments: 'ConfigEnvironments',
8 | environmenttypes: 'ConfigEnvironments',
9 | lbsettings: 'InfraConfigLBSettings',
10 | lbupstream: 'InfraConfigLBUpstream',
11 | permissions: 'InfraConfigPermissions',
12 | services: 'InfraConfigServices'
13 | };
14 |
15 | function logicalTableName(entityTypeName) {
16 | return logicalTableNames[entityTypeName];
17 | }
18 |
19 | module.exports = logicalTableName;
20 |
--------------------------------------------------------------------------------
/server/api/api-utils/notImplemented.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | function notImplemented(res, reason) {
6 | res.status(501);
7 | throw new Error(`Sorry, this action is not yet implemented: ${reason}`);
8 | }
9 |
10 | module.exports = notImplemented;
11 |
--------------------------------------------------------------------------------
/server/api/api-utils/requestMetadata.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let getMetadataForDynamoAudit = req => ({
6 | TransactionID: req.id,
7 | User: req.user.getName()
8 | });
9 |
10 | module.exports = {
11 | getMetadataForDynamoAudit
12 | };
13 |
--------------------------------------------------------------------------------
/server/api/api-utils/requestParam.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let fp = require('lodash/fp');
6 |
7 | module.exports = (name, req) => fp.get(['swagger', 'params', name, 'value'])(req);
8 |
--------------------------------------------------------------------------------
/server/api/controllers/diagnostics/diagnosticsController.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../../config');
6 | const clusterNode = require('../../../modules/clusterNode');
7 |
8 | function getHealthcheck(req, res) {
9 | res.json({
10 | OK: true,
11 | Version: config.get('APP_VERSION'),
12 | Leader: clusterNode.isLeader()
13 | });
14 | }
15 |
16 | module.exports = {
17 | getHealthcheck
18 | };
19 |
--------------------------------------------------------------------------------
/server/api/controllers/load-balancer/loadBalancerController.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let sender = require('../../../modules/sender');
6 | let ScanNginxUpstreams = require('../../../queryHandlers/ScanNginxUpstreams');
7 |
8 | /**
9 | * GET /load-balancer/{name}
10 | */
11 | function getLoadBalancer(req, res, next) {
12 | const fqdn = req.swagger.params.id.value;
13 |
14 | let query = {
15 | name: 'ScanNginxUpstreams',
16 | instanceDomainName: fqdn
17 | };
18 |
19 | return sender.sendQuery(ScanNginxUpstreams, { query })
20 | .then(data => res.json(data))
21 | .catch(next);
22 | }
23 |
24 | module.exports = {
25 | getLoadBalancer
26 | };
27 |
--------------------------------------------------------------------------------
/server/api/controllers/package-upload-url/dynamicResponseCreator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function create(status, value) {
4 | return response => response.format({
5 | 'text/plain': () => response.status(status).send(value),
6 | 'application/json': () => response.status(status).json({ url: value })
7 | });
8 | };
9 |
--------------------------------------------------------------------------------
/server/appspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.0
2 | os: linux
3 | files:
4 | - source: /
5 | destination: /opt/environment-manager
6 | hooks:
7 | ApplicationStop:
8 | - location: deployment/code-deploy/application-stop.sh
9 | runas: root
10 | BeforeInstall:
11 | - location: deployment/code-deploy/before-install.sh
12 | runas: root
13 | AfterInstall:
14 | - location: deployment/code-deploy/on-after-install.sh
15 | runas: root
16 | ApplicationStart:
17 | - location: deployment/code-deploy/application-start.sh
18 | runas: root
19 | ValidateService:
20 | - location: deployment/code-deploy/validate-service.sh
21 | runas: root
22 |
--------------------------------------------------------------------------------
/server/commands/aws/SetInstanceMaintenanceMode.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let serviceTargets = require('../../modules/service-targets');
6 |
7 | module.exports = function SetTargetMaintenanceState(command) {
8 | let accountName = command.accountName;
9 | let environment = command.instance.getTag('Environment');
10 | let host = command.instance.PrivateIpAddress;
11 | let enable = command.enable;
12 |
13 | return serviceTargets.setInstanceMaintenanceMode(accountName, host, environment, enable);
14 | };
15 |
--------------------------------------------------------------------------------
/server/commands/deployments/S3PathContract.schema.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | id: 'http://thetrainline.com/environment-manager/S3PathContract-schema#',
5 | $schema: 'http://json-schema.org/draft-04/schema#',
6 | title: 'S3PathContract',
7 | description: 'It represents the path of an object in S3',
8 | type: 'object',
9 | properties: {
10 | bucket: {
11 | description: 'Name of the S3 bucket',
12 | type: 'string'
13 | },
14 | key: {
15 | description: 'Name of the S3 key',
16 | type: 'string'
17 | }
18 | },
19 | required: [
20 | 'bucket',
21 | 'key'
22 | ]
23 | };
24 |
--------------------------------------------------------------------------------
/server/commands/services/DeleteTargetState.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | let serviceTargets = require('../../modules/service-targets');
7 | let schema = require('../../modules/schema/schema');
8 |
9 | module.exports = function DeleteTargetState(command) {
10 | return co(function* () {
11 | yield schema('DeleteTargetStateCommand').then(x => x.assert(command));
12 |
13 | let key = command.key;
14 | return yield serviceTargets.removeTargetState(command.environment, { key });
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/server/commands/services/UpdateTargetState.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let serviceTargets = require('../../modules/service-targets');
6 | let schema = require('../../modules/schema/schema');
7 | let DeploymentLogsStreamer = require('../../modules/DeploymentLogsStreamer');
8 | let deploymentLogsStreamer = new DeploymentLogsStreamer();
9 |
10 | module.exports = function UpdateTargetState(command) {
11 | let { deploymentId, key, options, value } = command;
12 | return schema('UpdateTargetStateCommand')
13 | .then(x => x.assert(command))
14 | .then(() => deploymentLogsStreamer.log(deploymentId, `Updating Consul key ${command.key}`))
15 | .then(() => serviceTargets.setTargetState(command.environment, { key, value, options }));
16 | };
17 |
--------------------------------------------------------------------------------
/server/config/version.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const VERSION_INFO = 'version.txt';
6 |
7 | let fs = require('fs');
8 | let packageInfo = require('../package.json');
9 |
10 | function getVersion() {
11 | if (fs.existsSync(VERSION_INFO)) {
12 | return fs.readFileSync(VERSION_INFO, 'utf-8').trim();
13 | } else {
14 | return `${packageInfo.version}-DEV`;
15 | }
16 | }
17 |
18 | module.exports = {
19 | getVersion
20 | };
21 |
--------------------------------------------------------------------------------
/server/deployment/code-deploy/application-start.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | systemctl enable environment-manager
4 | systemctl start environment-manager
5 |
--------------------------------------------------------------------------------
/server/deployment/code-deploy/application-stop.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if systemctl is-active environment-manager | grep "^active$"; then
4 | systemctl stop environment-manager
5 | fi
6 |
--------------------------------------------------------------------------------
/server/deployment/code-deploy/before-install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eux
4 |
--------------------------------------------------------------------------------
/server/deployment/code-deploy/on-after-install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | create_systemd_unit() {
4 | echo "Creating systemd unit ${1}" >&2
5 | local SERVICE_DEFINITION=$1
6 | local SRC_FILE=/opt/environment-manager/deployment/systemd/${SERVICE_DEFINITION}
7 | local TARGET_FILE=/lib/systemd/system/${SERVICE_DEFINITION}
8 |
9 | cp -f ${SRC_FILE} ${TARGET_FILE}
10 | chmod 644 ${TARGET_FILE}
11 | chown root.root ${TARGET_FILE}
12 | }
13 |
14 | create_systemd_unit "environment-manager.service"
15 | create_systemd_unit "environment-manager-debug.service"
16 |
17 | echo "Allowing execution of environment-manager start script" >&2
18 | chmod a+x /opt/environment-manager/start
--------------------------------------------------------------------------------
/server/deployment/code-deploy/validate-service.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set +e
4 |
5 | max_retries=10
6 | retries=0
7 | http_port=40500
8 |
9 | echo "Verifying the installation"
10 |
11 | url="https://127.0.0.1:$http_port/diagnostics/healthchecks/ping"
12 | echo "Service URL=$url"
13 |
14 | while [[ $retries -lt $max_retries ]]
15 | do
16 | if curl -k -s $url --insecure | grep "Success"; then
17 | echo "Got Success!"
18 | exit 0
19 | fi
20 | sleep 1
21 | ((retries++))
22 | done
23 |
24 | echo "max retries ($max_retries) reached, installation check failed"
25 | exit 1
26 |
--------------------------------------------------------------------------------
/server/deployment/systemd/environment-manager-debug.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Conflicts=environment-manager.service
3 |
4 | [Service]
5 | EnvironmentFile=/etc/environment-manager.env
6 | WorkingDirectory=/opt/environment-manager/
7 | ExecStart=/usr/bin/npm run start-debug
8 |
9 | Restart=always
10 | SyslogIdentifier=environment-manager-debug
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
--------------------------------------------------------------------------------
/server/deployment/systemd/environment-manager.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Conflicts=environment-manager-debug.service
3 |
4 | [Service]
5 | EnvironmentFile=/etc/environment-manager.env
6 | WorkingDirectory=/opt/environment-manager/
7 | ExecStart=/opt/environment-manager/start
8 |
9 | Restart=always
10 | StandardOutput=syslog
11 | StandardError=syslog
12 | SyslogIdentifier=environment-manager
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/server/healthchecks/sensu/healthchecks.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import requests
3 | from requests import ConnectionError
4 |
5 | from requests.packages.urllib3.exceptions import InsecureRequestWarning
6 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
7 |
8 | def success():
9 | print('Healthcheck passed')
10 | sys.exit(0)
11 |
12 | def fail(reason):
13 | print(reason)
14 | sys.exit(2)
15 |
16 | def run_check(name):
17 | url = 'https://localhost:40500/diagnostics/healthchecks/' + name
18 |
19 | try:
20 | response = requests.get(url, verify=False)
21 | except ConnectionError:
22 | fail('Could not connect to ' + url)
23 | except Exception as ex:
24 | fail('An error ocurred: ' + ex.message)
25 |
26 | if response.status_code == 200:
27 | success()
28 | else:
29 | fail(response.json()['reason'])
--------------------------------------------------------------------------------
/server/healthchecks/sensu/healthchecks.yml:
--------------------------------------------------------------------------------
1 | sensu_healthchecks:
2 | sensu_check1:
3 | name: enivornment-manager-ping
4 | local_script: ping.py
5 | interval: 10
6 | alert_after: 6
7 | tip: Checks that environment manager is reachable
8 | runbook: Check that the service is running properly
9 | sensu_check2:
10 | name: enivornment-manager-redis
11 | local_script: redis.py
12 | interval: 10
13 | alert_after: 6
14 | tip: Checks that environment manager can connect to the redis cluster it uses for user session storage
15 | runbook: Check the redis cluster is up and running
--------------------------------------------------------------------------------
/server/healthchecks/sensu/ping.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import healthchecks
3 | healthchecks.run_check('ping')
--------------------------------------------------------------------------------
/server/healthchecks/sensu/redis.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import healthchecks
3 | healthchecks.run_check('redis')
--------------------------------------------------------------------------------
/server/models/Deployment.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let _ = require('lodash');
6 | let deployments = require('../modules/data-access/deployments');
7 |
8 | class Deployment {
9 |
10 | constructor(data, expectedNodes = undefined) {
11 | _.assign(this, data);
12 | if (expectedNodes !== undefined) {
13 | _.assign(this, { ExpectedNodes: expectedNodes });
14 | }
15 | }
16 |
17 | static getById(key) {
18 | return deployments.get({ DeploymentID: key });
19 | }
20 | }
21 |
22 | module.exports = Deployment;
23 |
--------------------------------------------------------------------------------
/server/models/EnvironmentType.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let _ = require('lodash');
6 | let environmentDatabase = require('../modules/environmentDatabase');
7 |
8 | class EnvironmentType {
9 |
10 | constructor(data) {
11 | _.assign(this, data);
12 | }
13 |
14 | static getByName(name) {
15 | return environmentDatabase.getEnvironmentTypeByName(name);
16 | }
17 |
18 | }
19 |
20 | module.exports = EnvironmentType;
21 |
--------------------------------------------------------------------------------
/server/models/Image.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let _ = require('lodash');
6 | let sender = require('../modules/sender');
7 | let co = require('co');
8 | let ScanCrossAccountImages = require('../queryHandlers/ScanCrossAccountImages');
9 |
10 | class Image {
11 |
12 | constructor(data) {
13 | _.assign(this, data);
14 | }
15 |
16 | static getById(id) {
17 | return co(function* () {
18 | let images = yield sender.sendQuery(ScanCrossAccountImages, {
19 | query: {
20 | name: 'ScanCrossAccountImages'
21 | }
22 | });
23 | let image = _.find(images, { ImageId: id });
24 | return new Image(image);
25 | });
26 | // let image = yield imageProvider.get(awsLaunchConfig.ImageId);
27 | }
28 |
29 | }
30 |
31 | module.exports = Image;
32 |
--------------------------------------------------------------------------------
/server/models/Service.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let _ = require('lodash');
6 | let servicesDb = require('../modules/data-access/services');
7 |
8 | class Service {
9 |
10 | constructor(data) {
11 | _.assign(this, data);
12 | }
13 |
14 | static getByName(name) {
15 | return servicesDb.get({ ServiceName: name })
16 | .then(obj => (obj ? new Service(obj) : null));
17 | }
18 | }
19 |
20 | module.exports = Service;
21 |
--------------------------------------------------------------------------------
/server/models/TaggableMixin.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let _ = require('lodash');
6 |
7 | let TaggableMixin = Base => class extends Base {
8 | getTag(key, defaultValue) {
9 | let tag = _.find(this.Tags, { Key: key });
10 | if (tag === undefined) {
11 | if (arguments.length <= 1) {
12 | throw new Error(`Can't find tag "${key}"`);
13 | } else {
14 | return defaultValue;
15 | }
16 | }
17 | return tag.Value;
18 | }
19 |
20 | setTag(key, value) {
21 | let tag = this.getTag(key);
22 | if (tag === undefined) {
23 | tag = {
24 | Key: key,
25 | Value: value
26 | };
27 | this.Tags.push(tag);
28 | } else {
29 | tag.Value = value;
30 | }
31 | }
32 | };
33 |
34 | module.exports = TaggableMixin;
35 |
--------------------------------------------------------------------------------
/server/modules/PackagePathProvider.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let S3PathContract = require('./deployment/S3PathContract');
6 | let configCache = require('./configurationCache');
7 |
8 | module.exports = function PackagePathProvider() {
9 | this.getS3Path = function (deployment) {
10 | return configCache
11 | .getEnvironmentTypeByName(deployment.environmentTypeName)
12 | .then((environmentType) => {
13 | let filePath = `${deployment.environmentName}/${deployment.serviceName}`;
14 | let fileName = `${deployment.serviceName}-${deployment.serviceVersion}.zip`;
15 |
16 | return Promise.resolve(new S3PathContract({
17 | bucket: environmentType.DeploymentBucket,
18 | key: `${filePath}/${fileName}`
19 | }));
20 | });
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/server/modules/active-directory-adapter/activeDirectoryAdapterConfiguration.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 |
7 | module.exports = function ActiveDirectoryAdapterConfiguration() {
8 | let configuration;
9 |
10 | this.get = function getConfiguration() {
11 | if (!configuration) {
12 | configuration = config.getUserValue('local').ActiveDirectory;
13 | }
14 |
15 | return configuration;
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/server/modules/active-directory-adapter/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 | const mock = require('./activeDirectoryAdapter.mock.js');
7 | const prod = require('./activeDirectoryAdapter.prod.js');
8 |
9 | let Implementation = config.get('IS_PRODUCTION') ? prod : mock;
10 |
11 | module.exports = new Implementation();
12 |
--------------------------------------------------------------------------------
/server/modules/amazon-client/masterAccountClient.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let AWS = require('aws-sdk');
6 |
7 | module.exports = {
8 | createLowLevelDynamoClient: () => Promise.resolve(new AWS.DynamoDB()),
9 | createDynamoClient: () => Promise.resolve(new AWS.DynamoDB.DocumentClient()),
10 | createASGClient: () => Promise.resolve(new AWS.AutoScaling()),
11 | createEC2Client: () => Promise.resolve(new AWS.EC2()),
12 | createIAMClient: () => Promise.resolve(new AWS.IAM()),
13 | createS3Client: () => Promise.resolve(new AWS.S3()),
14 | createSNSClient: () => Promise.resolve(new AWS.SNS())
15 | };
16 |
--------------------------------------------------------------------------------
/server/modules/amazon-client/myIdentity.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let AWS = require('aws-sdk');
6 | let memoize = require('../memoize');
7 |
8 | let myIdentity = memoize(() => (new AWS.STS()).getCallerIdentity().promise());
9 |
10 | module.exports = myIdentity;
11 |
--------------------------------------------------------------------------------
/server/modules/authentication.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | function isUserAuthenticated(user) {
6 | return !!user;
7 | }
8 |
9 | module.exports = {
10 | allowUnknown(request, response, next) {
11 | return next();
12 | },
13 |
14 | denyUnauthorized(request, response, next) {
15 | // User not authenticated
16 | if (!isUserAuthenticated(request.user)) {
17 | response.status(403);
18 | response.json({
19 | error: 'Access denied. Please log in'
20 | });
21 | } else {
22 | next();
23 | }
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/server/modules/authentications/cookieAuthentication.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let userService = require('../user-service');
6 | let cookieAuthenticationConfiguration = require('./cookieAuthenticationConfiguration');
7 |
8 | module.exports = {
9 | middleware(req, res, next) {
10 | if (req.user) return next();
11 |
12 | let cookie = req.cookies[cookieAuthenticationConfiguration.getCookieName()];
13 | if (!cookie) return next();
14 |
15 | return userService.getUserByToken(cookie)
16 | .then((user) => {
17 | req.user = user;
18 | req.authenticatedBy = 'cookie';
19 | next();
20 | }, () => next());
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/server/modules/authentications/tokenAuthentication.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let userService = require('../user-service');
6 |
7 | const PATTERN = /bearer\s+(.*)/i;
8 |
9 | module.exports = {
10 | middleware(req, res, next) {
11 | if (req.user) return next();
12 |
13 | let authorization = req.headers.authorization;
14 | if (!authorization) return next();
15 |
16 | let match = PATTERN.exec(authorization);
17 | if (!match) return next();
18 |
19 | return userService.getUserByToken(match[1])
20 | .then((user) => {
21 | req.user = user;
22 | req.authenticatedBy = 'bearer';
23 | return next();
24 | }, (error) => {
25 | res.status(401);
26 | res.send(error.message);
27 | });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/server/modules/authentications/tokenAuthenticationConfiguration.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let config = require('../../config');
7 |
8 | function loadConfiguration() {
9 | let localConfig = config.getUserValue('local');
10 |
11 | assert(localConfig.authentication, 'missing \'authentication\' field in configuration');
12 | assert(localConfig.authentication.tokenDuration, 'missing \'authentication.tokenDuration\' field in configuration');
13 |
14 | return {
15 | tokenDuration: localConfig.authentication.tokenDuration
16 | };
17 | }
18 |
19 | module.exports = {
20 | getTokenDuration: () => {
21 | let configuration = loadConfiguration();
22 | return configuration.tokenDuration;
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/server/modules/authorizers/allow-authenticated.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | exports.getRules = () => Promise.resolve([]);
6 |
7 | exports.docs = {
8 | requiresClusterPermissions: false,
9 | requiresEnvironmentTypePermissions: false
10 | };
11 |
--------------------------------------------------------------------------------
/server/modules/authorizers/deployments.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | let deploymentsHelper = require('../queryHandlersUtil/deployments-helper');
7 |
8 | module.exports = {
9 | getRules(request) {
10 | return co(function* () {
11 | let key = request.swagger.params.id.value;
12 | let deployment = yield deploymentsHelper.get({ key });
13 |
14 | return [{
15 | resource: request.url.replace(/\/+$/, ''),
16 | access: request.method,
17 | clusters: [deployment.Value.OwningCluster],
18 | environmentTypes: [deployment.Value.EnvironmentType]
19 | }];
20 | });
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/server/modules/authorizers/instances.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let Instance = require('../../models/Instance');
6 | let co = require('co');
7 |
8 | exports.getRules = function getRules(request) {
9 | const id = request.swagger.params.id.value;
10 |
11 | return co(function* _() {
12 | const instance = yield Instance.getById(id);
13 | const owningCluster = instance.getTag('OwningCluster');
14 |
15 | return [{
16 | resource: request.url.replace(/\/+$/, ''),
17 | access: request.method,
18 | clusters: [owningCluster]
19 | }];
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/server/modules/authorizers/none.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | exports.getRules = () => Promise.resolve([]);
6 |
7 | exports.docs = {
8 | requiresClusterPermissions: false,
9 | requiresEnvironmentTypePermissions: false
10 | };
11 |
--------------------------------------------------------------------------------
/server/modules/authorizers/services.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | exports.getRules = (request) => {
6 | let body = request.params.body || request.body;
7 | let cluster = request.params.range || request.params.cluster || body.OwningCluster;
8 |
9 | return Promise.resolve([{
10 | resource: request.url.replace(/\/+$/, ''),
11 | access: request.method,
12 | clusters: [cluster.toLowerCase()]
13 | }]);
14 | };
15 |
16 | exports.docs = {
17 | requiresClusterPermissions: true,
18 | requiresEnvironmentTypePermissions: false
19 | };
20 |
--------------------------------------------------------------------------------
/server/modules/authorizers/simple.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | exports.getRules = request => Promise.resolve([{
6 | resource: request.url.replace(/\/+$/, ''),
7 | access: request.method
8 | }]);
9 |
10 | exports.docs = {
11 | requiresClusterPermissions: false,
12 | requiresEnvironmentTypePermissions: false
13 | };
14 |
--------------------------------------------------------------------------------
/server/modules/awsResourceNameProvider.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../config');
6 | let resourcePrefix = config.get('EM_AWS_RESOURCE_PREFIX');
7 |
8 | module.exports = {
9 | getTableName: tableName => `${resourcePrefix}${tableName}`
10 | };
11 |
--------------------------------------------------------------------------------
/server/modules/base64.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const buffer = require('buffer');
4 | const base64 = 'base64';
5 | const utf8 = 'utf8';
6 |
7 | let decode = str => JSON.parse(new buffer.Buffer(str, base64).toString(utf8));
8 |
9 | let encode = obj => new buffer.Buffer(JSON.stringify(obj), utf8).toString(base64);
10 |
11 | module.exports = {
12 | decode,
13 | encode
14 | };
15 |
--------------------------------------------------------------------------------
/server/modules/clientFactories/autoScalingGroupClientFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const asgResourceFactory = require('../../modules/resourceFactories/asgResourceFactory');
6 |
7 | module.exports = {
8 | create(parameters) {
9 | return asgResourceFactory.create(undefined, parameters);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/server/modules/clientFactories/ec2InstanceClientFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const ec2InstanceResourceFactory = require('../resourceFactories/ec2InstanceResourceFactory');
6 |
7 | module.exports = {
8 | create(parameters) {
9 | return ec2InstanceResourceFactory.create(undefined, parameters);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/server/modules/clientFactories/iamRoleClientFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let IAMRoleClient = require('./IAMRoleClient');
6 |
7 | module.exports = {
8 | create(parameters) {
9 | return new Promise((resolve) => {
10 | let client = new IAMRoleClient(parameters.accountName);
11 | resolve(client);
12 | });
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/server/modules/clientFactories/snsTopicClientFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let SNSTopicClient = require('./SNSTopicClient');
6 |
7 | module.exports = {
8 | create(parameters) {
9 | return new Promise((resolve) => {
10 | let client = new SNSTopicClient(parameters.accountName);
11 | resolve(client);
12 | });
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/server/modules/clusterNode.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const cluster = require('exp-leader-election');
4 | const logger = require('./logger');
5 | const config = require('../config').getUserValue('local');
6 |
7 | const consulConfig = {
8 | key: 'locks/envmgr/leader',
9 | consul: config.consul
10 | };
11 |
12 | let leader = false;
13 |
14 | cluster(consulConfig)
15 | .on('gainedLeadership', (...args) => {
16 | leader = true;
17 | logger.debug('Gained leadership', ...args);
18 | })
19 | .on('error', (err) => {
20 | if (leader) {
21 | logger.debug('Lost leadership');
22 | }
23 | leader = false;
24 | logger.error('Error during leader election / renewal', err);
25 | });
26 |
27 | module.exports = {
28 | isLeader: () => {
29 | return leader;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/server/modules/configuration/S3ConfigurationProvider.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let masterAccountClient = require('../amazon-client/masterAccountClient');
6 | let config = require('../../config');
7 |
8 | const S3_BUCKET = config.get('EM_AWS_S3_BUCKET');
9 | const S3_KEY = config.get('EM_AWS_S3_KEY');
10 |
11 | module.exports = function S3ConfigurationProvider() {
12 | this.get = function getConfigurationFromS3() {
13 | let parameters = {
14 | Bucket: S3_BUCKET,
15 | Key: S3_KEY
16 | };
17 |
18 | return masterAccountClient
19 | .createS3Client()
20 | .then(client => client.getObject(parameters).promise())
21 | .then(object => JSON.parse(object.Body.toString('utf8')));
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/server/modules/consul-client/clientConfig.mock.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | module.exports = parameters => (
6 | Promise.resolve({
7 | host: '10.249.16.74',
8 | port: '8500',
9 | defaults: {
10 | dc: 'tl-c50'
11 | },
12 | promisify: parameters.promisify
13 | })
14 | );
15 |
--------------------------------------------------------------------------------
/server/modules/consul-client/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 | let consul = require('consul');
7 | let mock = require('./clientConfig.mock.js');
8 | let prod = require('./clientConfig.prod.js');
9 |
10 | let clientConfig = config.get('IS_PRODUCTION') ? prod : mock;
11 |
12 | function createConfig(options) {
13 | return clientConfig(options);
14 | }
15 |
16 | function create(options) {
17 | return createConfig(options).then(newConfig => consul(newConfig));
18 | }
19 |
20 | module.exports = { createConfig, create };
21 |
--------------------------------------------------------------------------------
/server/modules/consul-node/consul-node.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | class ConsulNode {
4 | constructor(jsonRepresentation = {}) {
5 | this.json = jsonRepresentation;
6 | }
7 |
8 | getServiceVersion() {
9 | return this.json.ServiceTags.find(st => st.split(':')[0].toLowerCase() === 'version');
10 | }
11 |
12 | getJson() {
13 | return this.json;
14 | }
15 | }
16 |
17 | module.exports = {
18 | ConsulNode
19 | };
20 |
--------------------------------------------------------------------------------
/server/modules/consulDataStructures.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let { defaultTo, flow, get, groupBy, map, mapValues } = require('lodash/fp');
4 |
5 | function tagsOf(item) {
6 | function parseTag(str) {
7 | let sepIdx = str.indexOf(':');
8 | return [str.slice(0, sepIdx), str.slice(sepIdx + 1)];
9 | }
10 | return flow(
11 | get('Tags'),
12 | map(parseTag),
13 | groupBy(([key]) => key),
14 | mapValues(flow(
15 | map(([, value]) => value))))(item);
16 | }
17 |
18 | let valueOfTag = key => flow(tagsOf, get(key), defaultTo([]));
19 |
20 | module.exports = {
21 | tagsOf,
22 | valueOfTag
23 | };
24 |
--------------------------------------------------------------------------------
/server/modules/data-access/accounts.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'InfraConfigAccounts';
6 | const TTL = 600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/cachedSingleAccountDynamoTable.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let singleAccountDynamoTable = require('./singleAccountDynamoTable');
6 | let dynamoTableCache = require('./dynamoTableCache');
7 |
8 | function factory(physicalTableName, { ttl }) {
9 | let cachedTable = dynamoTableCache(physicalTableName, { ttl });
10 | return singleAccountDynamoTable(physicalTableName, cachedTable);
11 | }
12 |
13 | module.exports = factory;
14 |
--------------------------------------------------------------------------------
/server/modules/data-access/clusters.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'InfraConfigClusters';
6 | const TTL = 3600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/configEnvironmentTypes.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'ConfigEnvironmentTypes';
6 | const TTL = 600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/configEnvironments.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'ConfigEnvironments';
6 | const TTL = 600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/deploymentMaps.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'ConfigDeploymentMaps';
6 | const TTL = 600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/describeDynamoTable.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let { createLowLevelDynamoClient: DynamoDB } = require('../amazon-client/masterAccountClient');
6 | let memoize = require('../memoize');
7 |
8 | function describeTableArn(TableName) {
9 | return DynamoDB().then(dynamo => dynamo.describeTable({ TableName }).promise());
10 | }
11 |
12 | /**
13 | * @description Return a memoized description of a DynamoDB table
14 | * @param {string} TableName - The name of the table
15 | * @returns {object} - The table description
16 | */
17 | let describe = memoize(describeTableArn);
18 |
19 | module.exports = describe;
20 |
--------------------------------------------------------------------------------
/server/modules/data-access/loadBalancerSettings.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'InfraConfigLBSettings';
6 | const TTL = 600; // seconds
7 |
8 | let { getTableName: physicalTableName } = require('../awsResourceNameProvider');
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/notificationSettings.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'ConfigNotificationSettings';
6 | const TTL = 1200; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/data-access/permissions.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const LOGICAL_TABLE_NAME = 'InfraConfigPermissions';
6 | const TTL = 600; // seconds
7 |
8 | let physicalTableName = require('../awsResourceNameProvider').getTableName;
9 | let cachedSingleAccountDynamoTable = require('./cachedSingleAccountDynamoTable');
10 |
11 | module.exports = cachedSingleAccountDynamoTable(physicalTableName(LOGICAL_TABLE_NAME), { ttl: TTL });
12 |
--------------------------------------------------------------------------------
/server/modules/deployment/DeploymentContract.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let deploymentValidators = require('./deploymentValidators');
6 | let _ = require('lodash');
7 |
8 | class DeploymentContract {
9 |
10 | constructor(data) {
11 | _.assign(this, data);
12 | }
13 |
14 | validate(configuration) {
15 | // Checking deployment is valid through all validators otherwise return a rejected promise
16 | return deploymentValidators.map(validator => validator.validate(this, configuration));
17 | }
18 |
19 | }
20 |
21 |
22 | module.exports = DeploymentContract;
23 |
--------------------------------------------------------------------------------
/server/modules/deployment/S3PathContract.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | module.exports = function S3PathContract(options) {
6 | this.bucket = options.bucket;
7 | this.key = options.key;
8 | this.getType = () => this.constructor.name;
9 | };
10 |
--------------------------------------------------------------------------------
/server/modules/deployment/deploymentDefinition.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | function getKeyValue(deployment) {
6 | let deploymentId = deployment.id;
7 | let deploymentKeyValue = {
8 | key: `deployments/${deploymentId}/overall_status`,
9 | value: 'In Progress'
10 | };
11 |
12 | return Promise.resolve(deploymentKeyValue);
13 | }
14 |
15 | module.exports = {
16 | getKeyValue
17 | };
18 |
--------------------------------------------------------------------------------
/server/modules/deployment/deploymentValidators.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const blueGreenDeploymentValidator = require('./validators/blueGreenDeploymentValidator');
6 | const uniqueServiceVersionDeploymentValidator = require('./validators/uniqueServiceVersionDeploymentValidator');
7 |
8 | let validators = [
9 | blueGreenDeploymentValidator,
10 | uniqueServiceVersionDeploymentValidator
11 | ];
12 |
13 | module.exports = validators;
14 |
--------------------------------------------------------------------------------
/server/modules/deployment/serviceInstallationDefinition.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | function getKeyValue(deployment, s3Path) {
6 | let environmentName = deployment.environmentName;
7 | let serviceName = deployment.serviceName;
8 | let serviceVersion = deployment.serviceVersion;
9 |
10 | let serviceInstallationKeyValue = {
11 | key: `environments/${environmentName}/services/${serviceName}/${serviceVersion}/installation`,
12 | value: {
13 | PackageBucket: s3Path.bucket,
14 | PackageKey: s3Path.key,
15 | InstallationTimeout: 20 // Todo: Should be read from the service definition
16 | }
17 | };
18 |
19 | return Promise.resolve(serviceInstallationKeyValue);
20 | }
21 |
22 | module.exports = {
23 | getKeyValue
24 | };
25 |
--------------------------------------------------------------------------------
/server/modules/errors/ActiveDirectoryError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function ActiveDirectoryError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/AutoScalingGroupAlreadyExistsError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function AutoScalingGroupAlreadyExistsError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/AutoScalingGroupNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function AutoScalingGroupNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/AwsError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function AwsError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/BadRequestError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function BadRequestError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/ConfigurationError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function ConfigurationError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/DeploymentValidationError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let BaseError = require('./BaseError.class');
6 |
7 | module.exports = class DeploymentValidationError extends BaseError {
8 |
9 | constructor(message, innerError) {
10 | super();
11 | this.name = this.constructor.name;
12 | this.message = message;
13 | this.innerError = innerError;
14 |
15 | Error.captureStackTrace(this, this.constructor);
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/server/modules/errors/DynamoItemNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function DynamoItemNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/HttpRequestError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function HttpRequestError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/ImageNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function ImageNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InconsistentSlicesStatusError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InconsistentSlicesStatusError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InstanceNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InstanceNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InstanceProfileNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InstanceProfileNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InvalidContractError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InvalidContractError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InvalidCredentialsError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InvalidCredentialsError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InvalidItemSchemaError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InvalidItemSchemaError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/InvalidOperationError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function InvalidOperationError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/KeyPairNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function KeyPairNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/LaunchConfigurationAlreadyExistsError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function LaunchConfigurationAlreadyExistsError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/PackagePreparationError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function PackagePreparationError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/ResourceLockedError.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function ResourceLockedError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/ResourceNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function ResourceNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/RoleNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function RoleNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/errors/TopicNotFoundError.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let util = require('util');
6 | let BaseError = require('./BaseError.class');
7 |
8 | module.exports = function TopicNotFoundError(message, innerError) {
9 | this.name = this.constructor.name;
10 | this.message = message;
11 | this.innerError = innerError;
12 |
13 | Error.captureStackTrace(this, this.constructor);
14 | };
15 |
16 | util.inherits(module.exports, BaseError);
17 |
--------------------------------------------------------------------------------
/server/modules/express-middleware/deprecateMiddleware.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | /**
4 | * Express middleware that adds deprecated=true to a request and sets the Warning HTTP header
5 | * on the response if it is a request to a deprecated route.
6 | */
7 |
8 | 'use strict';
9 |
10 | function create(fn) {
11 | return function deprecateMiddleware(req, res, next) {
12 | try {
13 | let warning = fn(req);
14 | if (warning) {
15 | let now = new Date().toUTCString();
16 | res.locals.deprecated = true;
17 | res.append('Warning', `299 - Deprecated: ${warning} "${now}"`);
18 | }
19 | next();
20 | } catch (error) {
21 | next(error);
22 | }
23 | };
24 | }
25 |
26 | module.exports = create;
27 |
--------------------------------------------------------------------------------
/server/modules/express-middleware/swaggerNewRelicMiddleware.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const yaml = require('js-yaml');
5 | const fs = require('fs');
6 | const apiSpec = yaml.safeLoad(fs.readFileSync('api/swagger.yaml', 'utf8'));
7 | const API_BASE_PATH = apiSpec.basePath;
8 | const isNewRelicInUse = require('../new-relic/check');
9 |
10 | function newRelicSwaggerMiddleware(req, res, next) {
11 | let newrelic = require('newrelic'); // eslint-disable-line global-require
12 | newrelic.setTransactionName(path.join(API_BASE_PATH, req.path));
13 | next();
14 | }
15 |
16 | function newRelicSwaggerMiddlewareNoOp(req, res, next) {
17 | next();
18 | }
19 |
20 | const swaggerNewRelic = isNewRelicInUse() ? newRelicSwaggerMiddleware : newRelicSwaggerMiddlewareNoOp;
21 |
22 | module.exports = swaggerNewRelic;
23 |
--------------------------------------------------------------------------------
/server/modules/functional.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let when = (cond, fnTrue, fnFalse = () => null) =>
4 | x => (cond(x) ? fnTrue(x) : fnFalse(x));
5 |
6 | let hasValue = x =>
7 | (x !== null && x !== undefined);
8 |
9 | module.exports = {
10 | when,
11 | hasValue
12 | };
13 |
--------------------------------------------------------------------------------
/server/modules/health-checks/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let resultCodes = require('./resultCodes');
6 | const ping = require('./library/ping');
7 | const redis = require('./library/redis');
8 |
9 | let checks = [
10 | ping,
11 | redis
12 | // ... add more health checks here
13 | ];
14 |
15 | module.exports = {
16 | resultCodes,
17 | checks
18 | };
19 |
--------------------------------------------------------------------------------
/server/modules/health-checks/library/ping.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let HealthCheckResults = require('../resultCodes');
6 |
7 | module.exports = {
8 | url: '/ping',
9 | run: () => {
10 | return Promise.resolve({
11 | result: HealthCheckResults.SUCCESS
12 | });
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/server/modules/health-checks/library/redis.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 |
7 | let HealthCheckResults = require('../resultCodes');
8 | let UserSessionStore = require('../../userSessionStore');
9 |
10 | function getResult(status) {
11 | if (status === 'wait' || status === 'ready') {
12 | return { result: HealthCheckResults.SUCCESS };
13 | }
14 |
15 | return {
16 | result: HealthCheckResults.FAIL,
17 | reason: `Redis connection status is '${status}'`
18 | };
19 | }
20 |
21 | module.exports = {
22 | url: '/redis',
23 | run: () => {
24 | return co(function* () {
25 | let sessionStore = yield UserSessionStore.get();
26 | return getResult(sessionStore.status());
27 | });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/server/modules/health-checks/resultCodes.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | module.exports = {
6 | SUCCESS: 'Success',
7 | FAIL: 'Failed'
8 | };
9 |
--------------------------------------------------------------------------------
/server/modules/http-server-factory/HttpServerFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let http = require('http');
6 |
7 | function HttpServerFactory() {
8 | this.create = function (application, parameters) {
9 | return new Promise((resolve) => {
10 | let port = parameters.port;
11 | let server = http.createServer(application);
12 | server.listen(port, () => resolve(server));
13 | });
14 | };
15 | }
16 |
17 | module.exports = HttpServerFactory;
18 |
--------------------------------------------------------------------------------
/server/modules/http-server-factory/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 | const Ssl = require('./HttpsServerFactory');
7 | const NoSsl = require('./HttpServerFactory');
8 | let implementation;
9 |
10 | if (config.get('IS_PRODUCTION') && !config.get('USE_HTTP')) {
11 | implementation = new Ssl();
12 | } else {
13 | implementation = new NoSsl();
14 | }
15 |
16 | module.exports = implementation;
17 |
--------------------------------------------------------------------------------
/server/modules/new-relic/check.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | module.exports = () => process.env.NEW_RELIC_APP_NAME !== undefined;
6 |
--------------------------------------------------------------------------------
/server/modules/provisioning/Image.class.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 |
7 | module.exports = function Image(imageSummary) {
8 | assert(imageSummary, 'Expected "ami" argument not to be null.');
9 |
10 | this.id = imageSummary.ImageId;
11 | this.creationDate = imageSummary.CreationDate;
12 | this.platform = imageSummary.Platform;
13 | this.name = imageSummary.Name;
14 | this.description = imageSummary.Description;
15 | this.type = imageSummary.AmiType;
16 | this.version = imageSummary.AmiVersion;
17 | this.isCompatibleImage = imageSummary.IsCompatibleImage;
18 | this.encrypted = imageSummary.Encrypted;
19 | this.isStable = imageSummary.IsStable;
20 | this.rootVolumeSize = imageSummary.RootVolumeSize;
21 | };
22 |
--------------------------------------------------------------------------------
/server/modules/provisioning/launchConfiguration/userData/linux-user-data.txt:
--------------------------------------------------------------------------------
1 | #!/bin/bash -xe
2 | /etc/puppet/tools/machine_boot -t name=,environmenttype=${EnvironmentType},environment=${Environment},securityzone=${SecurityZone},owningcluster=${OwningCluster},role=${Role},contactemail=${ContactEmail},projectcode=${ProjectCode} ${PuppetRole} > /tmp/machine_boot.log
3 |
--------------------------------------------------------------------------------
/server/modules/provisioning/launchConfiguration/userData/windows-user-data.txt:
--------------------------------------------------------------------------------
1 |
2 | if(test-path "C:\TTLApps\ttl-appbootstrapper\configure.ps1"){
3 | Powershell.exe -executionpolicy remotesigned -File C:\TTLApps\ttl-appbootstrapper\configure.ps1
4 | } else {
5 | Powershell.exe -executionpolicy remotesigned -File C:\TTLApps\initial-boot.ps1
6 | }
7 |
8 | ##Creator:${ContactEmail}
9 | ##Environment:${Environment}
10 | ##Owner:${OwningCluster}
11 | ##Role:${Role}
12 | ##PuppetRole:${PuppetRole}
13 | ##DeploymentMaps:[]
14 | ##OwningCluster:${OwningCluster}
15 | ##EnvironmentType:${EnvironmentType}
16 | ##SecurityZone:${SecurityZone}
17 | ##ContactEmail:${ContactEmail}
18 | ##ProjectCode:${ProjectCode}
19 | ##RemovalDate:${RemovalDate}
20 |
--------------------------------------------------------------------------------
/server/modules/queryHandlersUtil/getASG.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | const asgResourceFactory = require('../../modules/resourceFactories/asgResourceFactory');
7 |
8 | function* handleQuery(query) {
9 | // Create an instance of the resource to work with based on the resource
10 | // descriptor and AWS account name.
11 | let parameters = { accountName: query.accountName };
12 | let resource = yield asgResourceFactory.create(undefined, parameters);
13 |
14 | // Get AutoScalingGroup by name
15 | return resource.get({ name: query.autoScalingGroupName, clearCache: query.clearCache });
16 | }
17 |
18 | module.exports = co.wrap(handleQuery);
19 |
--------------------------------------------------------------------------------
/server/modules/queryHandlersUtil/scanCrossAccount.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let sender = require('../sender');
6 | let scanCrossAccountFn = require('./scanCrossAccountFn');
7 |
8 | function scanCrossAccount(query, simpleScanQueryName) {
9 | function queryAccount(account) {
10 | let childQuery = Object.assign({ name: simpleScanQueryName, accountName: account.AccountName }, query);
11 | return sender.sendQuery({ query: childQuery, parent: query });
12 | }
13 | return scanCrossAccountFn(queryAccount);
14 | }
15 |
16 | module.exports = scanCrossAccount;
17 |
--------------------------------------------------------------------------------
/server/modules/queryHandlersUtil/scanCrossAccountFn.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let awsAccounts = require('../awsAccounts');
6 | let applyFuncToAccounts = require('./applyFuncToAccounts');
7 |
8 | function scanCrossAccountFn(fn) {
9 | return awsAccounts.all()
10 | .then(handleAccounts);
11 |
12 | function handleAccounts(accounts) {
13 | return applyFuncToAccounts(fn, accounts);
14 | }
15 | }
16 |
17 | module.exports = scanCrossAccountFn;
18 |
--------------------------------------------------------------------------------
/server/modules/resourceFactories/AsgResource.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let AsgResourceBase = require('./AsgResourceBase');
6 | let AutoScalingGroup = require('../../models/AutoScalingGroup');
7 |
8 | function AsgResource(accountId) {
9 | const base = new AsgResourceBase(accountId);
10 | const self = Object.create(new AsgResourceBase(accountId));
11 | self.get = function (parameters) {
12 | return base.get(parameters).then(x => new AutoScalingGroup(x));
13 | };
14 | self.all = function (parameters) {
15 | return base.all(parameters).then(xs => xs.map(x => new AutoScalingGroup(x)));
16 | };
17 | return self;
18 | }
19 |
20 | module.exports = AsgResource;
21 |
--------------------------------------------------------------------------------
/server/modules/resourceFactories/asgLifeCycleHooksResourceFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let amazonClientFactory = require('../amazon-client/childAccountClient');
6 | let AsgLifeCycleHooksResource = require('./AsgLifeCycleHooksResource');
7 | let logger = require('../logger');
8 |
9 | module.exports = {
10 |
11 | canCreate: resourceDescriptor => resourceDescriptor.type.toLowerCase() === 'asgs-scheduled-actions',
12 |
13 | create: (resourceDescriptor, parameters) => {
14 | logger.debug(`Getting ASG client for account "${parameters.accountName}"...`);
15 | return amazonClientFactory.createASGClient(parameters.accountName)
16 | .then(client => new AsgLifeCycleHooksResource(client));
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/server/modules/resourceFactories/asgScheduledActionsResourceFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let amazonClientFactory = require('../amazon-client/childAccountClient');
6 | let AsgScheduledActionsResource = require('./AsgScheduledActionsResource');
7 | let logger = require('../logger');
8 |
9 | module.exports = {
10 |
11 | canCreate: resourceDescriptor => resourceDescriptor.type.toLowerCase() === 'asgs-scheduled-actions',
12 |
13 | create: (resourceDescriptor, parameters) => {
14 | logger.debug(`Getting ASG client for account "${parameters.accountName}"...`);
15 | return amazonClientFactory.createASGClient(parameters.accountName)
16 | .then(client => new AsgScheduledActionsResource(client));
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/server/modules/resourceFactories/securityGroupResourceFactory.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let amazonClientFactory = require('../amazon-client/childAccountClient');
6 | let SecurityGroupResource = require('./SecurityGroupResource');
7 |
8 | module.exports = {
9 |
10 | canCreate: resourceDescriptor =>
11 | resourceDescriptor.type.toLowerCase() === 'ec2/sg',
12 |
13 | create: (resourceDescriptor, parameters) =>
14 | amazonClientFactory.createEC2Client(parameters.accountName).then(client => new SecurityGroupResource(client))
15 |
16 | };
17 |
--------------------------------------------------------------------------------
/server/modules/schema/AccountName.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "AccountName",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Account Name",
5 | "description": "An Account Name",
6 | "type": "string",
7 | "minLength": 1,
8 | "maxLength": 255,
9 | "pattern": "^[a-zA-Z ][0-9a-zA-Z\\.\\-_]*$"
10 | }
--------------------------------------------------------------------------------
/server/modules/schema/AccountNumber.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "AccountNumber",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Account Number",
5 | "description": "An AWS Account Number",
6 | "type": "string",
7 | "minLength": 12,
8 | "maxLength": 12,
9 | "pattern": "^[0-9]+$"
10 | }
--------------------------------------------------------------------------------
/server/modules/schema/ConsulConnectCommon.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "ConsulConnectCommon",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "ConsulConnectCommon",
5 | "description": "Set data required to connect to Consul",
6 | "type": "object",
7 | "properties": {
8 | "environment": { "$ref": "EnvironmentName" }
9 | },
10 | "required": ["environment"]
11 | }
--------------------------------------------------------------------------------
/server/modules/schema/ConsulKey.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "ConsulKey",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Consul Key",
5 | "description": "Consul Key-Value Store Key",
6 | "type": "string",
7 | "minLength": 1,
8 | "maxLength": 255
9 | }
--------------------------------------------------------------------------------
/server/modules/schema/EnvironmentName.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "EnvironmentName",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Environment Name",
5 | "description": "An Environment Name",
6 | "type": "string",
7 | "minLength": 1,
8 | "maxLength": 255,
9 | "pattern": "^[a-zA-Z][0-9a-zA-Z\\.\\-_]*$"
10 | }
11 |
--------------------------------------------------------------------------------
/server/modules/schema/GetTargetStateQuery.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "GetTargetStateQuery",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Get Target State Query",
5 | "description": "Query the value of the desired target state for a deployment",
6 | "type": "object",
7 | "allOf": [
8 | { "$ref": "ConsulConnectCommon" },
9 | { "$ref": "#/definitions/self" }
10 | ],
11 | "definitions": {
12 | "self": {
13 | "type": "object",
14 | "properties": {
15 | "key": { "$ref": "ConsulKey" },
16 | "name": {
17 | "type": "string",
18 | "pattern": "^GetTargetState$"
19 | },
20 | "recurse": {
21 | "type": "boolean"
22 | }
23 | },
24 | "required": ["key", "name"]
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/server/modules/schema/UpdateTargetStateCommand.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "UpdateTargetStateCommand",
3 | "$schema": "http://json-schema.org/draft-04/schema#",
4 | "title": "Update Target State Command",
5 | "description": "Update the the target state of a service",
6 | "type": "object",
7 | "allOf": [
8 | { "$ref": "ConsulConnectCommon" },
9 | { "$ref": "#/definitions/self" }
10 | ],
11 | "definitions": {
12 | "self": {
13 | "type": "object",
14 | "properties": {
15 | "deploymentId": {
16 | "type": "string"
17 | },
18 | "key": { "$ref": "ConsulKey" },
19 | "name": {
20 | "type": "string",
21 | "pattern": "^UpdateTargetState$"
22 | }
23 | },
24 | "required": ["deploymentId", "key", "name", "value"]
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/server/modules/serverFactoryConfiguration.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let config = require('../config');
7 |
8 | module.exports = function ServerFactoryConfiguration() {
9 | this.getPort = () => configuration.port;
10 |
11 | let loadConfiguration = function () {
12 | let configuration = config.getUserValue('local');
13 |
14 | assert(configuration.server, 'missing \'server\' field in configuration');
15 | assert(configuration.server.port, 'missing \'server.port\' field in configuration');
16 | return {
17 | port: configuration.server.port
18 | };
19 | };
20 |
21 | let configuration = loadConfiguration();
22 | };
23 |
--------------------------------------------------------------------------------
/server/modules/service-discovery/consul/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let {
6 | getAllServices,
7 | getService,
8 | getServiceHealth,
9 | getAllNodes,
10 | getNodesForService,
11 | getNode,
12 | getNodeHealth
13 | } = require('./consulCatalog');
14 |
15 | module.exports = {
16 | getAllServices,
17 | getService,
18 | getServiceHealth,
19 | getAllNodes,
20 | getNodesForService,
21 | getNode,
22 | getNodeHealth
23 | };
24 |
--------------------------------------------------------------------------------
/server/modules/service-discovery/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let consulReporter = require('./consul');
6 |
7 | /**
8 | * Service Discovery abstraction to allow easy switching
9 | * of service discovery frameworks.
10 | */
11 | module.exports = consulReporter;
12 |
--------------------------------------------------------------------------------
/server/modules/service-targets/consul/ConsulManager.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let Promise = require('bluebird');
6 | let logger = require('../../logger');
7 |
8 | module.exports = class ConsulManager {
9 | constructor(client) {
10 | this.client = client;
11 | }
12 |
13 | setServerMaintenanceMode(enable) {
14 | logger.debug(`consul: setting maintenance mode to ${enable}`);
15 | let promisified = Promise.promisify(this.client.agent.maintenance, { context: this.client.agent });
16 | return promisified({ enable, reason: 'Maintanance mode triggered from EnvironmentManager' }).catch((err) => {
17 | throw new Error(`Couldn't connect to consul client: ${err.message}`);
18 | });
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/server/modules/service-targets/consul/consulMacroManager.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let ConsulManager = require('./ConsulManager');
6 | let co = require('co');
7 | let consulClient = require('../../consul-client');
8 |
9 | function* setInstanceMaintenanceMode(accountName, host, environment, enable) {
10 | let options = { accountName, host, environment };
11 | let consulManager = yield consulClient.create(options).then(client => new ConsulManager(client));
12 |
13 | yield consulManager.setServerMaintenanceMode(enable);
14 | }
15 |
16 | module.exports = {
17 | setInstanceMaintenanceMode: co.wrap(setInstanceMaintenanceMode)
18 | };
19 |
--------------------------------------------------------------------------------
/server/modules/service-targets/consul/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let {
6 | setInstanceMaintenanceMode
7 | } = require('./consulMacroManager');
8 |
9 | let {
10 | getTargetState,
11 | setTargetState,
12 | removeTargetState,
13 | removeRuntimeServerRoleTargetState,
14 | getAllServiceTargets,
15 | getServiceDeploymentCause,
16 | getInstanceServiceDeploymentInfo
17 | } = require('./keyValueStore');
18 |
19 | module.exports = {
20 | getTargetState,
21 | setTargetState,
22 | removeTargetState,
23 | removeRuntimeServerRoleTargetState,
24 | setInstanceMaintenanceMode,
25 | getAllServiceTargets,
26 | getServiceDeploymentCause,
27 | getInstanceServiceDeploymentInfo
28 | };
29 |
--------------------------------------------------------------------------------
/server/modules/service-targets/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let consulUpdater = require('./consul');
6 |
7 | /**
8 | * Service Discovery abstraction to allow easy switching
9 | * of service discovery frameworks.
10 | */
11 | module.exports = consulUpdater;
12 |
--------------------------------------------------------------------------------
/server/modules/sns/EnvironmentManagerEvents/getTargetArn.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | module.exports = (ResponseMetadata) => {
6 | if (!ResponseMetadata.TopicArn) {
7 | throw new Error('ResponseMetadata does not contain a TopicArn value to extract.');
8 | }
9 |
10 | return ResponseMetadata.TopicArn;
11 | };
12 |
--------------------------------------------------------------------------------
/server/modules/sslComponentsRepository/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 | const mock = require('./sslComponentsRepository.mock.js');
7 | const prod = require('./sslComponentsRepository.prod.js');
8 |
9 | let implementation;
10 |
11 | if (config.get('IS_PRODUCTION')) {
12 | implementation = prod;
13 | } else {
14 | implementation = mock;
15 | }
16 |
17 | module.exports = implementation;
18 |
--------------------------------------------------------------------------------
/server/modules/systemUser.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let User = require('./user');
6 | let systemUser = User.new('System', null, [], [{ Access: 'ADMIN', Resource: '**' }]);
7 |
8 | module.exports = systemUser;
9 |
--------------------------------------------------------------------------------
/server/modules/toggleServiceStatus.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let sender = require('./sender');
6 | let ToggleTargetStatus = require('../commands/services/ToggleTargetStatus');
7 |
8 | function toggleServiceStatus({ environment, service, slice, enable, serverRole, user }) {
9 | const name = 'ToggleTargetStatus';
10 | const command = { name, environment, service, slice, enable, serverRole };
11 | return sender.sendCommand(ToggleTargetStatus, { user, command });
12 | }
13 |
14 | module.exports = {
15 | toggleServiceStatus
16 | };
17 |
--------------------------------------------------------------------------------
/server/modules/user-service/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../../config');
6 | const mock = require('./userService.mock');
7 | const Prod = require('./userService.prod');
8 | let implementation;
9 |
10 | if (config.get('IS_PRODUCTION')) {
11 | implementation = new Prod();
12 | } else {
13 | implementation = mock;
14 | }
15 |
16 | module.exports = implementation;
17 |
--------------------------------------------------------------------------------
/server/modules/userSessionStore.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let EncryptedRedisStore = require('./data-access/encryptedRedisStore');
6 | const USER_SESSION_STORE_INDEX = 1;
7 |
8 | let sessionStore;
9 |
10 | function createSessionStore() {
11 | sessionStore = EncryptedRedisStore.createStore(USER_SESSION_STORE_INDEX);
12 | return sessionStore;
13 | }
14 |
15 | module.exports = {
16 | get: () => { return sessionStore || createSessionStore(); }
17 | };
18 |
--------------------------------------------------------------------------------
/server/modules/utilities.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | /**
6 | * Attempts to parse a JSON string into an object, returning null on error
7 | *
8 | * @param raw {String} The raw JSON string
9 | * @returns {Object|null} The parsed Object or null if a parsing error occured.
10 | */
11 | function safeParseJSON(raw) {
12 | try {
13 | return JSON.parse(raw);
14 | } catch (exception) {
15 | return null;
16 | }
17 | }
18 |
19 | /**
20 | *
21 | * @param date
22 | * @param offset
23 | * @returns {*}
24 | */
25 | function offsetMilliseconds(date, offset) {
26 | date.setMilliseconds(date.getMilliseconds() + offset);
27 | return date;
28 | }
29 |
30 | module.exports = { safeParseJSON, offsetMilliseconds };
31 |
--------------------------------------------------------------------------------
/server/modules/validate/rule/serviceExists.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let log = require('../../logger');
6 | let servicesDb = require('../../data-access/services');
7 |
8 | /* Returns an error in the format specified at http://jsonapi.org/format/#errors
9 | * if the service does not exist.
10 | */
11 | function serviceExists(service) {
12 | let serviceNotFound = () => ({
13 | title: 'Service Not Found',
14 | detail: `service name: ${service}`
15 | });
16 | return servicesDb.get({ ServiceName: service })
17 | .then((rsp => (rsp ? [] : serviceNotFound())),
18 | (err) => {
19 | log.warn(err);
20 | return serviceNotFound();
21 | });
22 | }
23 |
24 | module.exports = serviceExists;
25 |
--------------------------------------------------------------------------------
/server/modules/weblink.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const url = require('url');
5 |
6 | function link(links) {
7 | return _.map(links, (href, rel) => [`<${url.format(href)}>`, `rel="${rel}"`].join('; '))
8 | .join(', ');
9 | }
10 |
11 | module.exports = { link };
12 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetASGState.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let getASGState = require('../modules/environment-state/getASGState');
6 |
7 | module.exports = function GetServerState(query) {
8 | return getASGState(query.environmentName, query.asgName);
9 | };
10 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetAutoScalingGroup.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let getASG = require('../modules/queryHandlersUtil/getASG');
7 |
8 | module.exports = function GetAutoScalingGroup(query) {
9 | assert(query.accountName);
10 | assert(query.autoScalingGroupName);
11 |
12 | return getASG(query);
13 | };
14 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetEnvironmentScheduleStatus.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let moment = require('moment');
6 | let OpsEnvironment = require('../models/OpsEnvironment');
7 |
8 | function handler(query) {
9 | return OpsEnvironment.getByName(query.environmentName).then((opsEnvironment) => {
10 | let schedule = opsEnvironment.getScheduleStatus(moment(query.date).toDate());
11 | return { status: schedule };
12 | });
13 | }
14 |
15 | module.exports = handler;
16 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetInstanceProfile.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const iamInstanceProfileResourceFactory = require('../modules/resourceFactories/iamInstanceProfileResourceFactory');
6 |
7 | module.exports = function GetInstanceProfile(query) {
8 | let parameters = { accountName: query.accountName };
9 | return iamInstanceProfileResourceFactory.create(undefined, parameters).then(resource =>
10 | resource.get({ instanceProfileName: query.instanceProfileName })
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetKeyPair.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let keypairFactory = require('../modules/factories/keypairFactory');
7 |
8 | module.exports = function GetKeyPairQueryHandler({ accountName, keyName }) {
9 | assert(accountName);
10 | assert(keyName);
11 |
12 | let parameters = { accountName };
13 | return keypairFactory.create(parameters)
14 | .then(resource => resource.get({ keyName }));
15 | };
16 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetRole.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let iamRoleClientFactory = require('../modules/clientFactories/iamRoleClientFactory');
6 |
7 | module.exports = function GetRoleQueryHandler(query) {
8 | return iamRoleClientFactory
9 | .create({ accountName: query.accountName })
10 | .then(client => client.get({ roleName: query.roleName }));
11 | };
12 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetServicePortConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let Service = require('../models/Service');
4 | let _ = require('lodash');
5 |
6 | const DEFAULT_PORT = 0;
7 |
8 | const getPort = (service, colour) => _.get(service, ['Value', `${colour}Port`]);
9 |
10 | function intOrDefault(maybePort) {
11 | let port = Number(maybePort);
12 | return Number.isInteger(port) ? port : DEFAULT_PORT;
13 | }
14 |
15 | function getServicePortConfig(serviceName) {
16 | let portConfig = { blue: DEFAULT_PORT, green: DEFAULT_PORT };
17 |
18 | if (serviceName === undefined || serviceName === '') {
19 | return Promise.resolve(portConfig);
20 | }
21 |
22 | return Service.getByName(serviceName.trim())
23 | .then(service => ({
24 | blue: intOrDefault(getPort(service, 'Blue')),
25 | green: intOrDefault(getPort(service, 'Green'))
26 | }));
27 | }
28 |
29 | module.exports = getServicePortConfig;
30 |
--------------------------------------------------------------------------------
/server/queryHandlers/GetTopic.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let snsTopicClientFactory = require('../modules/clientFactories/snsTopicClientFactory');
6 |
7 | module.exports = function GetTopicQueryHandler(query) {
8 | return snsTopicClientFactory
9 | .create({ accountName: query.accountName })
10 | .then(client => client.get({ topicName: query.topicName }));
11 | };
12 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanAutoScalingGroups.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | const asgResourceFactory = require('../modules/resourceFactories/asgResourceFactory');
7 |
8 | function* handler(query) {
9 | // Create an instance of the resource to work with based on the resource
10 | // descriptor and AWS account name.
11 | let parameters = { accountName: query.accountName };
12 | let resource = yield asgResourceFactory.create(undefined, parameters);
13 |
14 | return resource.all({ names: query.autoScalingGroupNames });
15 | }
16 |
17 | module.exports = co.wrap(handler);
18 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanCrossAccountAutoScalingGroups.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let scanCrossAccount = require('../modules/queryHandlersUtil/scanCrossAccount');
6 | let ScanAutoScalingGroups = require('./ScanAutoScalingGroups');
7 |
8 | module.exports = function ScanCrossAccountAutoScalingGroups(query) {
9 | return scanCrossAccount(ScanAutoScalingGroups, query, 'ScanAutoScalingGroups');
10 | };
11 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanCrossAccountInstances.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let scanCrossAccount = require('../modules/queryHandlersUtil/scanCrossAccountFn');
6 | let ScanInstances = require('./ScanInstances');
7 |
8 | module.exports = function ScanCrossAccountInstances(query) {
9 | return scanCrossAccount(handleInstance);
10 |
11 | function handleInstance({ AccountNumber }) {
12 | return ScanInstances(Object.assign({}, query, { accountName: AccountNumber }));
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanInstances.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const ec2InstanceResourceFactory = require('../modules/resourceFactories/ec2InstanceResourceFactory');
6 |
7 | module.exports = function ScanInstancesQueryHandler({ accountName, filter }) {
8 | return ec2InstanceResourceFactory.create(undefined, { accountName })
9 | .then(handleResourceFactory);
10 |
11 | function handleResourceFactory(x) {
12 | return x.all({ filter });
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanLaunchConfigurations.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const launchConfigurationResourceFactory = require('../modules/resourceFactories/launchConfigurationResourceFactory');
6 | let co = require('co');
7 |
8 | function* handler(query) {
9 | // Create an instance of the resource to work with based on the resource
10 | // descriptor and AWS account name.
11 | let parameters = { accountName: query.accountName };
12 | let resource = yield launchConfigurationResourceFactory.create('launchconfig', parameters);
13 |
14 | // Scan resource items
15 | return resource.all({ names: query.launchConfigurationNames });
16 | }
17 |
18 | module.exports = co.wrap(handler);
19 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanNginxUpstreams.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | const nginxUpstreamsResourceFactory = require('../modules/resourceFactories/nginxUpstreamsResourceFactory');
7 |
8 | function* handler(query) {
9 | // Create an instance of the Nginx resource
10 | let resource = yield nginxUpstreamsResourceFactory.create(undefined, {});
11 |
12 | // Scan resource items
13 | const params = { instanceDomainName: query.instanceDomainName };
14 |
15 | return resource.all(params);
16 | }
17 |
18 | module.exports = co.wrap(handler);
19 |
--------------------------------------------------------------------------------
/server/queryHandlers/ScanSecurityGroups.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | const securityGroupResourceFactory = require('../modules/resourceFactories/securityGroupResourceFactory');
6 |
7 | module.exports = function ScanSecurityGroupsQueryHandler(query) {
8 | let parameters = { accountName: query.accountName };
9 |
10 | return securityGroupResourceFactory.create(undefined, parameters).then((resource) => {
11 | let request = {
12 | vpcId: query.vpcId,
13 | groupIds: query.groupIds,
14 | groupNames: query.groupNames
15 | };
16 |
17 | return resource.scan(request);
18 | });
19 | };
20 |
--------------------------------------------------------------------------------
/server/queryHandlers/services/GetAllNodes.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let serviceDiscovery = require('../../modules/service-discovery');
6 |
7 | module.exports = function GetAllNodes(query) {
8 | return serviceDiscovery.getAllNodes(query.environment);
9 | };
10 |
--------------------------------------------------------------------------------
/server/queryHandlers/services/GetNode.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let serviceDiscovery = require('../../modules/service-discovery');
6 |
7 | module.exports = function GetNode(query) {
8 | return serviceDiscovery.getNode(query.environment, query.nodeName);
9 | };
10 |
--------------------------------------------------------------------------------
/server/queryHandlers/services/GetTargetState.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let co = require('co');
6 | let serviceTargets = require('../../modules/service-targets');
7 | let schema = require('../../modules/schema/schema');
8 |
9 | module.exports = function GetTargetState(query) {
10 | return co(function* () {
11 | yield schema('GetTargetStateQuery').then(x => x.assert(query));
12 |
13 | let key = query.key;
14 | let recurse = query.recurse;
15 |
16 | return yield serviceTargets.getTargetState(query.environment, { key, recurse });
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/server/queryHandlers/slices/GetSlicesByService.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let getSlices = require('../../modules/queryHandlersUtil/getSlices');
7 | let loadBalancerUpstreams = require('../../modules/data-access/loadBalancerUpstreams');
8 |
9 | module.exports = function GetSlicesByService(query) {
10 | assert.equal(typeof query.environmentName, 'string');
11 | assert.equal(typeof query.serviceName, 'string');
12 |
13 | return loadBalancerUpstreams.inEnvironmentWithService(query.environmentName, query.serviceName)
14 | .then(upstreams => getSlices.handleQuery(query, upstreams));
15 | };
16 |
--------------------------------------------------------------------------------
/server/queryHandlers/slices/GetSlicesByUpstream.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let assert = require('assert');
6 | let getSlices = require('../../modules/queryHandlersUtil/getSlices');
7 | let loadBalancerUpstreams = require('../../modules/data-access/loadBalancerUpstreams');
8 |
9 | module.exports = function GetSlicesByUpstream(query) {
10 | assert.equal(typeof query.environmentName, 'string');
11 | assert.equal(typeof query.upstreamName, 'string');
12 |
13 | return loadBalancerUpstreams.inEnvironmentWithUpstream(query.environmentName, query.upstreamName)
14 | .then(upstreams => getSlices.handleQuery(query, upstreams));
15 | };
16 |
--------------------------------------------------------------------------------
/server/routes/home.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../config');
6 | let renderer = require('../modules/renderer');
7 |
8 | const PUBLIC_DIR = config.get('PUBLIC_DIR');
9 |
10 | renderer.register('home', `${PUBLIC_DIR}/index.html`);
11 |
12 | module.exports = function (request, response) {
13 | renderer.render('home', {}, content => response.send(content));
14 | };
15 |
--------------------------------------------------------------------------------
/server/scripts/command.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict';
3 |
4 | function getAction() {
5 |
6 | return process.argv[2];
7 |
8 | }
9 |
10 | function getParameters() {
11 |
12 | var result = { };
13 |
14 | process.argv.slice(3).forEach(arg => {
15 |
16 | var keyValue = arg.split("=");
17 |
18 | var key = keyValue[0].toLowerCase();
19 | if (!key) return;
20 |
21 | var value = keyValue[1] || null;
22 |
23 | result[key] = value;
24 |
25 | });
26 |
27 | return result;
28 |
29 | }
30 |
31 | module.exports = {
32 | action: getAction(),
33 | parameters: getParameters()
34 | };
--------------------------------------------------------------------------------
/server/scripts/preinstall.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 | 'use strict';
3 |
4 | let fs = require('fs');
5 | let path = require('path');
6 |
7 | linkModules();
8 |
9 | function linkModules() {
10 | let dir = 'modules';
11 | let target = path.join(__dirname, '..', dir);
12 | let link = path.join(__dirname, '..', 'node_modules', dir);
13 |
14 | let ln = (tgt, lnk, i) => {
15 | try {
16 | fs.symlinkSync(target, link, 'junction');
17 | } catch (error) {
18 | if (error.code === 'EEXIST' && 0 < i) {
19 | fs.unlinkSync(lnk);
20 | ln(tgt, lnk, i - 1);
21 | } else {
22 | throw error;
23 | }
24 | }
25 | };
26 |
27 | ln(target, link, 1);
28 | }
29 |
--------------------------------------------------------------------------------
/server/start:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # This script is called by systemd to start environment-manager
4 | # it sets up the environment and then runs Environment Manager
5 | # in place of the shell
6 |
7 | # Use the EC2 metadata service to look up the AWS region in which this server is running
8 | # and set the region Environment Manager will use when querying its management resources
9 | export EM_AWS_REGION=$(curl --silent --show-error http://169.254.169.254/2016-09-02/dynamic/instance-identity/document | jq --raw-output '.region')
10 | echo "EM_AWS_REGION=${EM_AWS_REGION}" >&2
11 |
12 | exec /usr/bin/node index.js
--------------------------------------------------------------------------------
/server/test/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'env': {
3 | 'mocha': true
4 | },
5 | 'rules': {
6 | 'func-names': 0,
7 | 'no-warning-comments': 1,
8 | 'prefer-arrow-callback': 0
9 | }
10 | };
--------------------------------------------------------------------------------
/server/test/bootstrap.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | let config = require('../config');
6 | let localConfig = require('../configuration.sample');
7 |
8 | config.setUserValue('local', localConfig);
9 |
--------------------------------------------------------------------------------
/server/test/modules/base64Test.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | 'use strict';
4 |
5 | let should = require('should');
6 | let base64 = require('../../modules/base64');
7 |
8 | describe('base64', function () {
9 | describe('when I encode then decode an object', function () {
10 | it('the result is the same as the argument', function () {
11 | let input = {
12 | number: 5.6,
13 | string: 'blah',
14 | array: [1, 2, 3],
15 | object: { a: 1 },
16 | };
17 | let result = base64.decode(base64.encode(input));
18 | result.should.be.eql(input);
19 | });
20 | });
21 | });
22 |
23 |
--------------------------------------------------------------------------------
/server/test/modules/emCryptoTest.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* eslint-env mocha */
4 |
5 | 'use strict'
6 |
7 | require('should');
8 | let sut = require('../../modules/emCrypto');
9 |
10 | describe('decrypting an encrypted value', function () {
11 | it('returns the input value', function () {
12 | let input = 'Hello World!';
13 | let password = 'my simple password';
14 | let ciphertext = sut.encrypt(password, input);
15 | let plaintext = sut.decrypt(password, ciphertext);
16 | plaintext.should.match(input);
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/server/test/modules/instances.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/server/test/modules/instances.spec.js
--------------------------------------------------------------------------------
/server/test/modules/service-reporter/service-reporterTest.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 | 'use strict';
5 |
6 | let assert = require('assert');
7 |
8 | describe('service-discovery', function() {
9 |
10 | let sut;
11 | beforeEach(() => sut = require('../../../modules/service-discovery'));
12 |
13 | it('exports the expected API', () => {
14 | assert.notEqual(sut.getAllServices, undefined, 'getAllServices is required');
15 | assert.notEqual(sut.getService, undefined, 'getService is required');
16 | assert.notEqual(sut.getAllNodes, undefined, 'getAllNodes is required');
17 | assert.notEqual(sut.getNode, undefined, 'getNode is required');
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/server/test/modules/service-updater/service-updaterTest.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 | 'use strict';
5 |
6 | let assert = require('assert');
7 |
8 | describe('service-targets', function() {
9 |
10 | let sut;
11 | beforeEach(() => sut = require('../../../modules/service-targets'));
12 |
13 | it('exports the expected API', () => {
14 | assert.notEqual(sut.getTargetState, undefined, 'getTargetState is required');
15 | assert.notEqual(sut.setTargetState, undefined, 'setTargetState is required');
16 | assert.notEqual(sut.removeTargetState, undefined, 'removeTargetState is required');
17 | assert.notEqual(sut.setInstanceMaintenanceMode, undefined, 'setInstanceMaintenanceMode is required');
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/server/test/schema-validation/environment-type.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "Subnets": {
3 | "PrivateApp": {
4 | "AvailabilityZoneA": "xxx",
5 | "AvailabilityZoneB": "xxx",
6 | "AvailabilityZoneC": "xxx"
7 | }
8 | },
9 | "SchemaVersion": 5,
10 | "VpcId": "xxx",
11 | "AWSAccountNumber": "123456789123",
12 | "NamingPattern": "c[0-9]{1,2}",
13 | "DeploymentBucket": "xxx",
14 | "LoadBalancers": [
15 | "xxx"
16 | ],
17 | "AWSAccountName": "xxx",
18 | "Consul": {
19 | "DataCenter": "xxx",
20 | "SecurityTokenPath": {
21 | "Bucket": "xxx",
22 | "Key": "xxx"
23 | },
24 | "Servers": [
25 | "10.249.17.254"
26 | ],
27 | "Port": 8500
28 | },
29 | "PuppetBranch": "xxx"
30 | }
--------------------------------------------------------------------------------
/server/test/test-profile.json:
--------------------------------------------------------------------------------
1 | {
2 | "EM_AWS_REGION": "eu-west-1",
3 | "EM_AWS_RESOURCE_PREFIX": "EnvironmentManagerTests-",
4 | "EM_LOG_LEVEL": "Silent",
5 | "EM_PACKAGES_BUCKET": "EM_PACKAGES_BUCKET"
6 | }
7 |
--------------------------------------------------------------------------------
/server/test/utils/fakeLogger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let nothing = () => undefined;
4 |
5 | module.exports = {
6 | debug: nothing,
7 | info: nothing,
8 | log: nothing,
9 | warn: nothing,
10 | error: nothing
11 | };
12 |
--------------------------------------------------------------------------------
/server/test/utils/sinonHelper.js:
--------------------------------------------------------------------------------
1 | /* TODO: enable linting and fix resulting errors */
2 | /* eslint-disable */
3 | /* Copyright (c) Trainline Limited, 2016-2017. All rights reserved. See LICENSE.txt in the project root for license information. */
4 | 'use strict';
5 |
6 | function SinonHelper() {
7 |
8 | this.getCalls = function (spy) {
9 |
10 | var calls = [];
11 | var call = null;
12 | var index = 0;
13 |
14 | while (!!(call = spy.getCall(index))) {
15 |
16 | calls.push(call);
17 | index++;
18 |
19 | }
20 |
21 | return calls;
22 |
23 | };
24 |
25 | }
26 |
27 | module.exports = new SinonHelper();
28 |
29 |
--------------------------------------------------------------------------------
/setup/cloudformation/.eslintrc.yaml:
--------------------------------------------------------------------------------
1 | env:
2 | es6: true
3 | node: true
4 | extends: eslint:recommended
5 | parserOptions:
6 | ecmaVersion: 6
--------------------------------------------------------------------------------
/setup/cloudformation/.gitignore:
--------------------------------------------------------------------------------
1 | *.template.json
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/.eslintignore:
--------------------------------------------------------------------------------
1 | /node_modules/**/*.*
2 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "airbnb",
3 | "validateIndentation": 2
4 | }
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraAsgLambdaScale/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infraAsgLambdaScale",
3 | "version": "0.0.1",
4 | "description": "Test gulp project with governator",
5 | "main": "index.js",
6 | "scripts": {
7 | "build-aws-resource": "pack-zip",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "",
11 | "license": "MIT",
12 | "devDependencies": {
13 | "gulp": "~3.8.10",
14 | "gulp-awslambda": "0.2.2",
15 | "gulp-zip": "~2.0.2",
16 | "pack-zip": "^0.2.2"
17 | }
18 | }
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraAsgLambdaScale/test.js:
--------------------------------------------------------------------------------
1 | var lambda = require("./index.js");
2 |
3 | //test with a lambda event
4 |
5 | lambda.handler({ detail: { requestParameters: { AutoScalingGroupName: "asgLambdaTest6" } } }, {
6 | fail: function(m) { console.log("fail:" + m) },
7 | success: function(m) { console.log("Success:" + m) }
8 | });
9 |
10 | //test with an SNS event:
11 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerAudit/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infra-environment-manager-audit",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "author": "",
7 | "license": "Apache-2.0",
8 | "dependencies": {},
9 | "scripts": {
10 | "build-aws-resource": "pack-zip",
11 | "lint": "eslint",
12 | "test": "tape **/*.spec.js"
13 | },
14 | "eslintConfig": {
15 | "env": {
16 | "es6": true,
17 | "node": true
18 | },
19 | "extends": "eslint:recommended",
20 | "parserOptions": {
21 | "ecmaVersion": 6
22 | },
23 | "rules": {
24 | "no-console": 0
25 | }
26 | },
27 | "devDependencies": {
28 | "eslint": "^3.4.0",
29 | "pack-zip": "^0.2.2",
30 | "proxyquire": "^1.8.0",
31 | "tape": "^4.7.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerAuditBackup/AwsAccount.js:
--------------------------------------------------------------------------------
1 | function AwsAccount(name, number) {
2 | var $this = this;
3 |
4 | $this.name = name;
5 | $this.number = number;
6 |
7 | $this.toString = function() {
8 | return $this.name + '[' + $this.number + ']';
9 | };
10 | }
11 |
12 | module.exports = AwsAccount;
13 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerAuditBackup/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infra-environment-manager-backup",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "author": "",
7 | "license": "ISC",
8 | "dependencies": {
9 | "async": "^1.5.2"
10 | },
11 | "scripts": {
12 | "build-aws-resource": "pack-zip",
13 | "lint": "eslint"
14 | },
15 | "eslintConfig": {
16 | "env": {
17 | "es6": true,
18 | "node": true
19 | },
20 | "extends": "eslint:recommended",
21 | "parserOptions": {
22 | "ecmaVersion": 6
23 | },
24 | "rules": {
25 | "no-console": 0
26 | }
27 | },
28 | "devDependencies": {
29 | "eslint": "^3.4.0",
30 | "pack-zip": "^0.2.2"
31 | }
32 | }
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerBackup/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infra-environment-manager-backup",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "author": "",
7 | "license": "ISC",
8 | "dependencies": {
9 | "async": "^1.5.2"
10 | },
11 | "devDependencies": {
12 | "pack-zip": "^0.2.2"
13 | },
14 | "scripts": {
15 | "build-aws-resource": "pack-zip"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerConfigurationChangeAudit/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | /* eslint-disable no-console */
6 |
7 | console.log('Loading InfraEnvironmentManagerConfigurationChangeAudit function');
8 |
9 | exports.handler = (event, context, callback) => {
10 | console.log('function InfraEnvironmentManagerConfigurationChangeAudit starting...');
11 | const attributes = event.Records[0].Sns.MessageAttributes;
12 | const attributeString = Object.keys(attributes).map(key => `${key}:${attributes[key].Value}`).join(',');
13 | console.log('Configuration Change Attributes:', attributeString);
14 | const message = event.Records[0].Sns.Message;
15 | console.log('Configuration Change SNS:', message);
16 | callback(null, message);
17 | };
18 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerOperationsChangeAudit/index.js:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Trainline Limited. All rights reserved. See LICENSE.txt in the project root for license information. */
2 |
3 | 'use strict';
4 |
5 | /* eslint-disable no-console */
6 |
7 | console.log('Loading InfraEnvironmentManagerOperationsChangeAudit function');
8 |
9 | exports.handler = (event, context, callback) => {
10 | console.log('function InfraEnvironmentManagerOperationsChangeAudit starting...');
11 | const attributes = event.Records[0].Sns.MessageAttributes;
12 | const attributeString = Object.keys(attributes).map(key => `${key}:${attributes[key].Value}`).join(',');
13 | console.log('Operations Change Attributes:', attributeString);
14 | const message = event.Records[0].Sns.Message;
15 | console.log('Operations Change SNS:', message);
16 | callback(null, message);
17 | };
18 |
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerScheduler/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let archiver = require('archiver-promise');
4 | let fs = require('fs-extra');
5 | let co = require('co');
6 |
7 | let config = require('./package.json');
8 |
9 | co(function* () {
10 | let { name, version } = config;
11 | let outDir = 'out';
12 | let destination = `${outDir}/${name}-${version}.zip`;
13 |
14 | yield fs.remove(outDir).then(() => fs.mkdir(outDir));
15 | yield zipFiles(__dirname, config.files, destination);
16 |
17 | console.log(destination);
18 | });
19 |
20 | function zipFiles(path, files, destination) {
21 | let archive = archiver(destination);
22 | archive.pipe(fs.createWriteStream(destination));
23 | files.forEach(file => archive.glob(file, { cwd: path }));
24 | return archive.finalize();
25 | }
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/InfraEnvironmentManagerScheduler/local/config.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "em": {
3 | "host": "https://environment-manager-domain-name",
4 | "credentials": {
5 | "username": "username",
6 | "password": "password"
7 | }
8 | },
9 | "limitToAccounts": [],
10 | "whatIf": true,
11 | "listSkippedInstances": true,
12 | "ignoreASGInstances": false,
13 | "errorOnFailure": true
14 | }
--------------------------------------------------------------------------------
/setup/cloudformation/lambda/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lambda",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha --recursive ./test --EM_PROFILE test/test-profile.json",
8 | "test-watch": "mocha --watch --recursive ./test --EM_PROFILE test/test-profile.json"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "aws-sdk": "^2.26.0",
14 | "eslint": "^3.17.1",
15 | "eslint-config-airbnb-base": "^11.1.1",
16 | "eslint-plugin-import": "^2.2.0",
17 | "mocha": "^3.2.0",
18 | "rewire": "^2.5.2",
19 | "sinon": "^1.17.7"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/setup/cloudformation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "environment-manager-stack",
3 | "version": "0.0.1",
4 | "description": "CloudFormation Stacks for Environment Manager",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "node tools/index.js build",
8 | "deploy": "node tools/index.js deploy",
9 | "prepublish": "cfn-packager install-subpackages",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": {
13 | "name": "Platform Development",
14 | "email": "platform.development@thetrainline.com"
15 | },
16 | "license": "Apache-2.0",
17 | "devDependencies": {
18 | "cfn-packager": "0.1.0"
19 | },
20 | "dependencies": {
21 | "bluebird": "^3.5.0",
22 | "commander": "^2.9.0",
23 | "globby": "^6.1.0",
24 | "js-yaml": "^3.8.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/setup/consul-acl/consul-deployment-agent.json:
--------------------------------------------------------------------------------
1 | {
2 | "key": {
3 | "": {
4 | "policy": "read"
5 | },
6 | "environments/": {
7 | "policy": "read"
8 | },
9 | "deployments/": {
10 | "policy": "write"
11 | }
12 | },
13 | "service": {
14 | "": {
15 | "policy": "read"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/setup/consul-acl/environment-manager.json:
--------------------------------------------------------------------------------
1 | {
2 | "key": {
3 | "": {
4 | "policy": "read"
5 | },
6 | "environments/": {
7 | "policy": "write"
8 | },
9 | "deployments/": {
10 | "policy": "write"
11 | }
12 | },
13 | "service": {
14 | "": {
15 | "policy": "read"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/setup/consul-acl/upstreamr.json:
--------------------------------------------------------------------------------
1 | {
2 | "key": {
3 | "": {
4 | "policy": "read"
5 | }
6 | },
7 | "service": {
8 | "": {
9 | "policy": "read"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/setup/data-migration/replicate-dynamodb-table/.eslintrc.yaml:
--------------------------------------------------------------------------------
1 | env:
2 | es6: true
3 | node: true
4 | extends:
5 | - eslint:recommended
--------------------------------------------------------------------------------
/setup/data-migration/replicate-dynamodb-table/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "replicate-dynamodb-table",
3 | "version": "0.1.0",
4 | "description": "AWS Lambda Function to replicate changes from one DynamoDB table to another",
5 | "main": "index.js",
6 | "author": "merlin.taylor@thetrainline.com",
7 | "license": "Apache-2.0",
8 | "scripts": {
9 | "test": "tap *.spec.js"
10 | },
11 | "devDependencies": {
12 | "eslint": "^4.5.0",
13 | "proxyquire": "^1.8.0",
14 | "tap": "^10.7.2"
15 | },
16 | "dependencies": {
17 | "aws-sdk": "^2.102.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/setup/data-migration/touch-dynamodb-table/.eslintrc.yaml:
--------------------------------------------------------------------------------
1 | env:
2 | es6: true
3 | node: true
4 | extends:
5 | - eslint:recommended
--------------------------------------------------------------------------------
/setup/data-migration/touch-dynamodb-table/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "touch-dynamodb-table",
3 | "version": "0.1.0",
4 | "description": "AWS Lambda Function to touch each record in a DynamoDB table",
5 | "main": "index.js",
6 | "author": "merlin.taylor@thetrainline.com",
7 | "license": "Apache-2.0",
8 | "scripts": {
9 | "test": "tap *.spec.js"
10 | },
11 | "devDependencies": {
12 | "eslint": "^4.5.0",
13 | "proxyquire": "^1.8.0",
14 | "tap": "^10.7.2"
15 | },
16 | "dependencies": {
17 | "aws-sdk": "^2.102.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/setup/linux-sample-package.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/setup/linux-sample-package.zip
--------------------------------------------------------------------------------
/setup/terraform/upstreamCleaner/aws_iam_role.tf:
--------------------------------------------------------------------------------
1 | resource "aws_iam_role" "upstream_cleaner" {
2 | name = "upstream_cleaner"
3 |
4 | assume_role_policy = < {
5 | browser.url('http://localhost:8080');
6 | },
7 | navigateToEnvironments: () => {
8 | browser.click('#environmentsLink');
9 | },
10 | navigateToOperations: () => {
11 | browser.click('#operationsLink');
12 | },
13 | navigateToCompare: () => {
14 | browser.click('#compareLink');
15 | },
16 | navigateToConfiguration: () => {
17 | browser.click('#configurationLink');
18 | browser.waitForVisible('#configServicesLink');
19 | }
20 | };
--------------------------------------------------------------------------------
/test/pages/login-page.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | module.exports = {
4 | logOut: () => {
5 | if (browser.isVisible('#logout')) {
6 | browser.click('#logout > a');
7 | browser.waitForVisible('#username');
8 | }
9 | },
10 | logIn: (username, password) => {
11 | if (browser.isVisible('#logout')) {
12 | browser.click('#logout > a');
13 | browser.waitForVisible('#username');
14 | }
15 | browser.setValue('#username', username || 'anyUser');
16 | browser.setValue('#password', password || 'anyPassword');
17 | browser.click('#sign-in');
18 | browser.waitForVisible('#logout');
19 | }
20 | };
--------------------------------------------------------------------------------
/test/test/test-ui/screenshots/ERROR_chrome_2018-05-15T12-41-26.078Z.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trainline/environment-manager/c84623a5f64cebe68a1afd4fec09821cc5d8ddad/test/test/test-ui/screenshots/ERROR_chrome_2018-05-15T12-41-26.078Z.png
--------------------------------------------------------------------------------