Skip to content

Commit

Permalink
merge tkexp
Browse files Browse the repository at this point in the history
  • Loading branch information
takashi kawase committed Oct 21, 2020
2 parents 5d5d51a + f3a9851 commit cf64f20
Show file tree
Hide file tree
Showing 40 changed files with 9,654 additions and 2,013 deletions.
35 changes: 35 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
version: 2
jobs:
build:

branches:
only:
- master

working_directory: ~/neuronbridge-services

docker:
- image: circleci/openjdk:8u171-jdk

environment:
TERM: dumb

steps:

- checkout

- restore_cache:
keys:
- neuronbridge-{{ checksum "search/pom.xml" }}
# fallback to using the latest cache if no exact match is found
- neuronbridge

- run: mvn clean install -f search/pom.xml

- save_cache:
key: neuronbridge-{{ checksum "search/pom.xml" }}
paths:
- ~/.m2

- run: mvn package -f search/pom.xml

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
.serverless
node_modules
local
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ As a prerequisite, you need to have the [AWS CLI](https://aws.amazon.com/cli/) i
NeuronBridge compute alignment requires an AMI instance preconfigured with ECS and with all required volumes mounted as expected by the alignment batch job.

To create the AMI use these steps:
* start an [Amazon ECS-optimized Amazon Linux AMI](https://aws.amazon.com/marketplace/search/results?x=0&y=0&searchTerms=Amazon+ECS-Optimized+Amazon+Linux+AMI&page=1&ref_=nav_search_box).
* start an [Amazon ECS-optimized Amazon Linux AMI](https://aws.amazon.com/marketplace/search/results?x=0&y=0&searchTerms=Amazon+ECS-Optimized+Amazon+Linux+AMI&page=1&ref_=nav_search_box).

* tart the EC2 instance
* run the following commands that mount the expected volumes:
* start the EC2 instance
* run the following commands that mount the expected volumes:

```
sudo yum -y update
Expand All @@ -39,10 +39,46 @@ The command above will create the compute environment, the job definition and th

### Deploy NeuronBridge¸ color depth search stack

Make sure you have built all the java packages with jdk 1.8 and maven:

```
mvnw clean package
```


In order to create the color depth search lambdas run:

```
cd search
npm install
npm run sls -- deploy -s dev
```

To deploy with different search limits:
```
PER_DAY_SEARCH_LIMITS=2 CONCURRENT_SEARCH_LIMITS=2 npm run sls -- deploy -s cgdev
```
Note: a negative value for a limit means unlimited.

To update a single function, once you have a seployed stack

```
npm run sls -- deploy function -f <function_name> -s dev
```

### Alignment Parameters
* force_voxel_size - if true it uses resolution parameters provided by the user
* xy_resolution
* z_resolution
* reference_channel
* number of slots (not exposed to the user)


### Color Depth Search Parameters:

* dataThreshold - default: 100
* maskThreshold - default: 100
* pixColorFluctuation (zSliceRange) - default: 2
* xyShift - default: 2
* mirrorMask - default: true
* minMatchingPixRatio - default: 2
47 changes: 41 additions & 6 deletions align/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,30 @@ resources:
InstanceRole: ecsInstanceRole
Tags: ${self:provider.stackTags}

ComputeAlignmentJobQueue:
ComputeAlignmentOnDemandEnv:
Type: AWS::Batch::ComputeEnvironment
Properties:
Type: MANAGED
State: ENABLED
ServiceRole: !Ref BatchServiceRole
ComputeEnvironmentName: "#{AWS::StackName}-align-ondemand-compute-env"
ComputeResources:
Type: EC2
MinvCpus: 0
DesiredvCpus: 0
MaxvCpus: 64
InstanceTypes:
- optimal
ImageId: ${self:custom.ec2AlignmentImageId}
Subnets:
- ${self:custom.subnetId}
SecurityGroupIds:
- ${self:custom.securityGroupId}
Ec2KeyPair: ${self:custom.sshKeyPairName}
InstanceRole: ecsInstanceRole
Tags: ${self:provider.stackTags}

LowPriorityComputeAlignmentJobQueue:
Type: AWS::Batch::JobQueue
Properties:
ComputeEnvironmentOrder:
Expand All @@ -80,6 +103,16 @@ resources:
Priority: 100
JobQueueName: "${self:service}-${self:provider.stage}-align-job-queue-lowpriority"

HighPriorityComputeAlignmentJobQueue:
Type: AWS::Batch::JobQueue
Properties:
ComputeEnvironmentOrder:
- Order: 0
ComputeEnvironment: !Ref ComputeAlignmentOnDemandEnv
State: ENABLED
Priority: 200
JobQueueName: "${self:service}-${self:provider.stage}-align-job-queue-highpriority"

ComputeAlignmentJobDefinition:
Type: "AWS::Batch::JobDefinition"
Properties:
Expand All @@ -96,9 +129,9 @@ resources:
inputs_bucket: ${self:custom.alignInputBucket}
outputs_bucket: ${self:custom.alignOutputBucket}
templates_dir: ${self:custom.alignmentTemplatesFolder}
xy_resolution: ""
z_resolution: ""
nchannels: 2
xy_resolution: "0"
z_resolution: "0"
reference_channel: "Signal_amount"
force_voxel_size: false
nslots: ${self:custom.defaultAlignmentThreads}
ContainerProperties:
Expand All @@ -124,8 +157,8 @@ resources:
- "Ref::xy_resolution"
- "--zres"
- "Ref::z_resolution"
- "--nchannels"
- "Ref::nchannels"
- "--reference-channel"
- "Ref::reference_channel"
- "--forceVxSize"
- "Ref::force_voxel_size"
- "--nslots"
Expand Down Expand Up @@ -155,6 +188,8 @@ resources:
Value: xvfb
- Name: SEARCH_UPDATE_FUNCTION
Value: ${file(../search/serverless.yml):service}-${self:provider.stage}-searchUpdate
- Name: ALIGNMENT_MEMORY
Value: 8G
ReadonlyRootFilesystem: true
Privileged: true
LinuxParameters:
Expand Down
10 changes: 6 additions & 4 deletions config.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
config:
project: NeuronBridge
stage: ${opt:stage, "tkjsdev"}
stage: ${opt:stage, tkjsdev}
version: 2.0.0
libraryBucket: janelia-flylight-color-depth-dev
libraryThumbnailsBucket: janelia-flylight-color-depth-thumbnails-dev
alignmentTemplatesBucket: janelia-flylight-color-depth-dev
libraryBucket: janelia-flylight-color-depth-${env:IMAGE_DATA_LEVEL, 'dev'}
libraryThumbnailsBucket: janelia-flylight-color-depth-thumbnails-${env:IMAGE_DATA_LEVEL, 'dev'}
alignmentTemplatesBucket: janelia-flylight-color-depth-${env:IMAGE_DATA_LEVEL, 'dev'}
searchBucket: janelia-neuronbridge-masks-tkdev
perDaySearchLimits: ${env:PER_DAY_SEARCH_LIMITS, 100}
concurrentSearchLimits: ${env:CONCURRENT_SEARCH_LIMITS, 10}
tracing: true
debug: true
13 changes: 13 additions & 0 deletions search/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"env": {
"commonjs": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
}
}
51 changes: 51 additions & 0 deletions search/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## Test Event for Color Depth Search Dispatch:

```
{
"libraryAlignmentSpace": "JRC2018_Unisex_20x_HR",
"searchableMIPSFolder": "searchable_neurons",
"libraries": [
"FlyEM_Hemibrain_v1.1"
],
"searchInputName": "mask1417367048598452966.png",
"searchInputFolder": "colorDepthTestData/test1",
"dataThreshold": 100,
"maskThreshold": 100,
"pixColorFluctuation": 2,
"xyShift": 2,
"mirrorMask": true
}
```

Note that libraryAlignmentSpace and searchableMIPSFolder, if specified will apply to all libraries from the list.
It is also possible to simply invoke it without specifying the libraryAlignmentSpace and/or the searchableMIPFolder
as below:
```
{
"libraries": [
"JRC2018_Unisex_20x_HR/FlyEM_Hemibrain_v1.1/searchable_neurons"
],
"searchInputName": "mask3900813784977233932.png",
"searchInputFolder": "colorDepthTestData/test2",
"dataThreshold": 100,
"maskThreshold": 100,
"pixColorFluctuation": 2,
"xyShift": 2,
"mirrorMask": true
}
```

## Unit testing

Simply run:
```
npm test
```

## Integration testing

This runs a local client which invokes the search dispatch, waits for the search to run, and then analyzes the search performance in various ways.

```
npm run-script search janelia-neuronbridge-cds-dev src/test/resources/test1.json
```
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ $util.qr($context.args.input.put("pixColorFluctuation", $util.defaultIfNull($ctx
$util.qr($context.args.input.put("xyShift", $util.defaultIfNull($ctx.args.input.xyShift, 2)))
$util.qr($context.args.input.put("mirrorMask", $util.defaultIfNull($ctx.args.input.mirrorMask, true)))
$util.qr($context.args.input.put("minMatchingPixRatio", $util.defaultIfNull($ctx.args.input.minMatchingPixRatio, 2)))
$util.qr($context.args.input.put("maxResultsPerMask", $util.defaultIfNull($ctx.args.input.negativeRadius, -1)))
$util.qr($context.args.input.put("createdOn", $util.defaultIfNull($ctx.args.input.createdOn, $util.time.nowISO8601())))
$util.qr($context.args.input.put("updatedOn", $util.defaultIfNull($ctx.args.input.updatedOn, $util.time.nowISO8601())))
$util.qr($context.args.input.put("__typename", "Search"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@
## [End] Determine request authentication mode **
## [Start] Check authMode and execute owner/group checks **
#if( $authMode == "userPools" )
## No Static Group Authorization Rules **

## [Start] Static Group Authorization Checks **
#set($isStaticGroupAuthorized = $util.defaultIfNull(
$isStaticGroupAuthorized, false))
## Authorization rule: { allow: groups, groups: ["neuronbridge-admin"], groupClaim: "cognito:groups" } **
#set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
#set( $allowedGroups = ["neuronbridge-admin"] )
#foreach( $userGroup in $userGroups )
#if( $allowedGroups.contains($userGroup) )
#set( $isStaticGroupAuthorized = true )
#break
#end
#end
## [End] Static Group Authorization Checks **

## No Dynamic Group Authorization Rules **

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#set( $limit = $util.defaultIfNull($context.args.limit, 10) )
#set( $ListRequest = {
"version": "2017-02-28",
"limit": $limit
} )
#if( $context.args.nextToken )
#set( $ListRequest.nextToken = $context.args.nextToken )
#end
#if( $context.args.filter )
#set( $ListRequest.filter = $util.parseJson("$util.transform.toDynamoDBFilterExpression($ctx.args.filter)") )
#end
#if( !$util.isNull($modelQueryExpression)
&& !$util.isNullOrEmpty($modelQueryExpression.expression) )
$util.qr($ListRequest.put("operation", "Query"))
$util.qr($ListRequest.put("query", $modelQueryExpression))
#if( !$util.isNull($ctx.args.sortDirection) && $ctx.args.sortDirection == "DESC" )
#set( $ListRequest.scanIndexForward = false )
#else
#set( $ListRequest.scanIndexForward = true )
#end
#else
$util.qr($ListRequest.put("operation", "Scan"))
#end
$util.toJson($ListRequest)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## [Start] Determine request authentication mode **
#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) )
#set( $authMode = "userPools" )
#end
## [End] Determine request authentication mode **
## [Start] Check authMode and execute owner/group checks **
#if( $authMode == "userPools" )
## [Start] Static Group Authorization Checks **
#set($isStaticGroupAuthorized = $util.defaultIfNull(
$isStaticGroupAuthorized, false))
## Authorization rule: { allow: groups, groups: ["neuronbridge-admin"], groupClaim: "cognito:groups" } **
#set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
#set( $allowedGroups = ["neuronbridge-admin"] )
#foreach( $userGroup in $userGroups )
#if( $allowedGroups.contains($userGroup) )
#set( $isStaticGroupAuthorized = true )
#break
#end
#end
## [End] Static Group Authorization Checks **

## [Start] If not static group authorized, filter items **
#if( !$isStaticGroupAuthorized )
#set( $items = [] )
#foreach( $item in $ctx.result.items )
## No Dynamic Group Authorization Rules **


## [Start] Owner Authorization Checks **
#set( $isLocalOwnerAuthorized = false )
## Authorization rule: { allow: owner, ownerField: "owner", identityClaim: "cognito:username" } **
#set( $allowedOwners0 = $item.owner )
#set( $identityValue = $util.defaultIfNull($ctx.identity.claims.get("username"), $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), "___xamznone____")) )
#if( $util.isList($allowedOwners0) )
#foreach( $allowedOwner in $allowedOwners0 )
#if( $allowedOwner == $identityValue )
#set( $isLocalOwnerAuthorized = true )
#end
#end
#end
#if( $util.isString($allowedOwners0) )
#if( $allowedOwners0 == $identityValue )
#set( $isLocalOwnerAuthorized = true )
#end
#end
## [End] Owner Authorization Checks **


#if( ($isLocalDynamicGroupAuthorized == true || $isLocalOwnerAuthorized == true) )
$util.qr($items.add($item))
#end
#end
#set( $ctx.result.items = $items )
#end
## [End] If not static group authorized, filter items **
#end
## [End] Check authMode and execute owner/group checks **

$util.toJson($context.result)
Loading

0 comments on commit cf64f20

Please sign in to comment.