├── .gitignore ├── .travis.yml ├── README.md └── serverless ├── .Rbuildignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── R ├── generate_deployment_config.R └── tmp_arm_deployments.R ├── inst └── arm-templates │ └── aci-logicapp │ ├── parameters.json │ └── template.json ├── man └── generate_deployment_config.Rd ├── serverless.Rproj └── tests ├── testthat.R └── testthat └── test_sample.R /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | 8 | # Example code in package build process 9 | *-Ex.R 10 | 11 | # Output files from R CMD build 12 | /*.tar.gz 13 | 14 | # Output files from R CMD check 15 | /*.Rcheck/ 16 | 17 | # RStudio files 18 | .Rproj.user/ 19 | 20 | # produced vignettes 21 | vignettes/*.html 22 | vignettes/*.pdf 23 | 24 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 25 | .httr-oauth 26 | 27 | # knitr and R markdown default cache directories 28 | /*_cache/ 29 | /cache/ 30 | 31 | # Temporary files created by R markdown 32 | *.utf8.md 33 | *.knit.md 34 | 35 | # Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html 36 | rsconnect/ 37 | .Rproj.user 38 | 39 | .DS_Store 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | 7 | before_install: 8 | - cd serverless 9 | 10 | # safelist 11 | branches: 12 | only: 13 | - master 14 | - development -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/harlecin/serverless.svg?branch=master)](https://travis-ci.com/harlecin/serverless) 2 | [![Join the chat at https://gitter.im/r_serverless/community](https://badges.gitter.im/r_serverless/community.svg)](https://gitter.im/r_serverless/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 3 | 4 | # serverless 5 | A package to help deploy serverless R functions to AWS and Azure using: 6 | - Container-as-a-Service and 7 | - Functions-as-a-Service 8 | -------------------------------------------------------------------------------- /serverless/.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.travis\.yml$ 4 | -------------------------------------------------------------------------------- /serverless/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: serverless 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre")) 5 | Description: What the package does (one paragraph). 6 | Depends: R (>= 3.4) 7 | License: MIT + file LICENSE 8 | Encoding: UTF-8 9 | LazyData: true 10 | Suggests: testthat 11 | Imports: 12 | yaml 13 | RoxygenNote: 6.0.1 14 | -------------------------------------------------------------------------------- /serverless/LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 -------------------------------------------------------------------------------- /serverless/LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /serverless/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | import(yaml) 4 | -------------------------------------------------------------------------------- /serverless/R/generate_deployment_config.R: -------------------------------------------------------------------------------- 1 | #' Generate config file 2 | #' 3 | #' Generates a config file in current working directory to specify which services 4 | #' should be created and deployed 5 | #' 6 | #' @param name Service name 7 | #' @param provider Cloud service provider to use. Currently supported "azure" 8 | #' @param type Specify if you want to deploy as container or as function 9 | #' @import yaml 10 | generate_deployment_config = function(name, provider, type='container') { 11 | 12 | if (type == 'container') { 13 | yaml::write_yaml(list(name = name, 14 | provider = provider, 15 | services = list(compute = 'aci', 16 | registry = 'acr', 17 | trigger = 'http' 18 | ) 19 | ), 20 | file = "./serverless.yaml", 21 | indent = 2) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /serverless/R/tmp_arm_deployments.R: -------------------------------------------------------------------------------- 1 | library(httr) 2 | library(AzureRMR) 3 | 4 | # Your tenant_id/directory_id -> azure portal/azure active directory/Properties/directory id 5 | tenant_id = "" 6 | 7 | # azure subscription -> azure portal/subscriptions 8 | subscription = "" 9 | 10 | resource_group = "serverless" 11 | location = "westeurope" 12 | 13 | 14 | az = create_azure_login(tenant = tenant_id) 15 | 16 | sub = az$get_subscription(subscription) 17 | 18 | ## Maybe deploy a template instead with rg$deploy_template? 19 | sub$create_resource_group(resource_group, location) 20 | 21 | ## Create ACR using template 22 | rg = sub$get_resource_group(resource_group) 23 | 24 | registry_name = "acrserverlesstest" 25 | 26 | ## ACI parameters 27 | parameters = list( 28 | registryName = registry_name, 29 | registryLocation = location, 30 | registrySKU = "Basic", 31 | adminUserEnabled = FALSE 32 | ) 33 | 34 | ## Why is the parameters.json template not working? 35 | tpl = rg$deploy_template(name = "ACR", 36 | template = "../../data/az-templates/acr-templates/template.json", 37 | parameters = parameters 38 | ) 39 | -------------------------------------------------------------------------------- /serverless/inst/arm-templates/aci-logicapp/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "workflows_latest_name": { 6 | "value": null 7 | }, 8 | "containerGroups_@{encodeURIComponent('containergroupname2')}_externalid": { 9 | "value": null 10 | }, 11 | "containerGroups_@{encodeURIComponent(body('Create_container_group')?['name'])}_externalid": { 12 | "value": null 13 | }, 14 | "connections_aci_externalid": { 15 | "value": null 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /serverless/inst/arm-templates/aci-logicapp/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "workflows_latest_name": { 6 | "defaultValue": "latest", 7 | "type": "String" 8 | }, 9 | "containerGroups_@{encodeURIComponent('containergroupname2')}_externalid": { 10 | "defaultValue": "/subscriptions/@{encodeURIComponent('a946be7b-3533-413d-9366-91e10c0b209b')}/resourceGroups/@{encodeURIComponent('serverless')}/providers/Microsoft.ContainerInstance/containerGroups/@{encodeURIComponent('containergroupname2')}", 11 | "type": "String" 12 | }, 13 | "containerGroups_@{encodeURIComponent(body('Create_container_group')?['name'])}_externalid": { 14 | "defaultValue": "/subscriptions/@{encodeURIComponent('a946be7b-3533-413d-9366-91e10c0b209b')}/resourceGroups/@{encodeURIComponent('serverless')}/providers/Microsoft.ContainerInstance/containerGroups/@{encodeURIComponent(body('Create_container_group')?['name'])}", 15 | "type": "String" 16 | }, 17 | "connections_aci_externalid": { 18 | "defaultValue": "/subscriptions/a946be7b-3533-413d-9366-91e10c0b209b/resourceGroups/serverless/providers/Microsoft.Web/connections/aci", 19 | "type": "String" 20 | } 21 | }, 22 | "variables": {}, 23 | "resources": [ 24 | { 25 | "type": "Microsoft.Logic/workflows", 26 | "apiVersion": "2017-07-01", 27 | "name": "[parameters('workflows_latest_name')]", 28 | "location": "westeurope", 29 | "properties": { 30 | "state": "Enabled", 31 | "definition": { 32 | "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", 33 | "contentVersion": "1.0.0.0", 34 | "parameters": { 35 | "$connections": { 36 | "defaultValue": {}, 37 | "type": "Object" 38 | } 39 | }, 40 | "triggers": { 41 | "manual": { 42 | "type": "Request", 43 | "kind": "Http", 44 | "inputs": { 45 | "schema": {} 46 | } 47 | } 48 | }, 49 | "actions": { 50 | "Create_container_group": { 51 | "runAfter": {}, 52 | "type": "ApiConnection", 53 | "inputs": { 54 | "body": { 55 | "location": "westeurope", 56 | "properties": { 57 | "containers": [ 58 | { 59 | "name": "containername2", 60 | "properties": { 61 | "command": [ 62 | "Rscript -e 'cat(1+1)'" 63 | ], 64 | "image": "rocker/r-base", 65 | "resources": { 66 | "requests": { 67 | "cpu": 2, 68 | "memoryInGB": 1 69 | } 70 | } 71 | } 72 | } 73 | ], 74 | "osType": "Linux", 75 | "restartPolicy": "Never" 76 | } 77 | }, 78 | "host": { 79 | "connection": { 80 | "name": "@parameters('$connections')['aci']['connectionId']" 81 | } 82 | }, 83 | "method": "put", 84 | "path": "[parameters('containerGroups_@{encodeURIComponent('containergroupname2')}_externalid')]", 85 | "queries": { 86 | "x-ms-api-version": "2017-10-01-preview" 87 | } 88 | } 89 | }, 90 | "Until": { 91 | "actions": { 92 | "Condition": { 93 | "actions": { 94 | "Delete_container_group": { 95 | "runAfter": { 96 | "Get_logs_of_a_container": [ 97 | "Succeeded" 98 | ] 99 | }, 100 | "type": "ApiConnection", 101 | "inputs": { 102 | "host": { 103 | "connection": { 104 | "name": "@parameters('$connections')['aci']['connectionId']" 105 | } 106 | }, 107 | "method": "delete", 108 | "path": "[parameters('containerGroups_@{encodeURIComponent(body('Create_container_group')?['name'])}_externalid')]", 109 | "queries": { 110 | "x-ms-api-version": "2017-10-01-preview" 111 | } 112 | } 113 | }, 114 | "Get_logs_of_a_container": { 115 | "runAfter": {}, 116 | "type": "ApiConnection", 117 | "inputs": { 118 | "host": { 119 | "connection": { 120 | "name": "@parameters('$connections')['aci']['connectionId']" 121 | } 122 | }, 123 | "method": "get", 124 | "path": "/subscriptions/@{encodeURIComponent('a946be7b-3533-413d-9366-91e10c0b209b')}/resourceGroups/@{encodeURIComponent('serverless')}/providers/Microsoft.ContainerInstance/containerGroups/@{encodeURIComponent(body('Get_properties_of_a_container_group')?['name'])}/containers/@{encodeURIComponent('containername2')}/logs", 125 | "queries": { 126 | "x-ms-api-version": "2017-10-01-preview" 127 | } 128 | } 129 | } 130 | }, 131 | "runAfter": { 132 | "Get_properties_of_a_container_group": [ 133 | "Succeeded" 134 | ] 135 | }, 136 | "else": { 137 | "actions": { 138 | "Delay": { 139 | "runAfter": {}, 140 | "type": "Wait", 141 | "inputs": { 142 | "interval": { 143 | "count": 10, 144 | "unit": "Second" 145 | } 146 | } 147 | } 148 | } 149 | }, 150 | "expression": { 151 | "and": [ 152 | { 153 | "equals": [ 154 | "@body('Get_properties_of_a_container_group')?['properties']?['instanceView']?['state']", 155 | "Succeeded" 156 | ] 157 | } 158 | ] 159 | }, 160 | "type": "If" 161 | }, 162 | "Get_properties_of_a_container_group": { 163 | "runAfter": {}, 164 | "type": "ApiConnection", 165 | "inputs": { 166 | "host": { 167 | "connection": { 168 | "name": "@parameters('$connections')['aci']['connectionId']" 169 | } 170 | }, 171 | "method": "get", 172 | "path": "[parameters('containerGroups_@{encodeURIComponent(body('Create_container_group')?['name'])}_externalid')]", 173 | "queries": { 174 | "x-ms-api-version": "2017-10-01-preview" 175 | } 176 | } 177 | } 178 | }, 179 | "runAfter": { 180 | "Create_container_group": [ 181 | "Succeeded" 182 | ] 183 | }, 184 | "expression": "@equals(body('Create_container_group')?['properties']?['instanceView']?['state'], 'Succeeded')", 185 | "limit": { 186 | "count": 60, 187 | "timeout": "PT1H" 188 | }, 189 | "type": "Until" 190 | } 191 | }, 192 | "outputs": {} 193 | }, 194 | "parameters": { 195 | "$connections": { 196 | "value": { 197 | "aci": { 198 | "connectionId": "[parameters('connections_aci_externalid')]", 199 | "connectionName": "aci", 200 | "id": "/subscriptions/a946be7b-3533-413d-9366-91e10c0b209b/providers/Microsoft.Web/locations/westeurope/managedApis/aci" 201 | } 202 | } 203 | } 204 | } 205 | } 206 | } 207 | ] 208 | } -------------------------------------------------------------------------------- /serverless/man/generate_deployment_config.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/generate_deployment_config.R 3 | \name{generate_deployment_config} 4 | \alias{generate_deployment_config} 5 | \title{Generate config file} 6 | \usage{ 7 | generate_deployment_config(name, provider, type = "container") 8 | } 9 | \arguments{ 10 | \item{name}{Service name} 11 | 12 | \item{provider}{Cloud service provider to use. Currently supported "azure"} 13 | 14 | \item{type}{Specify if you want to deploy as container or as function} 15 | } 16 | \description{ 17 | Generates a config file in current working directory to specify which services 18 | should be created and deployed 19 | } 20 | -------------------------------------------------------------------------------- /serverless/serverless.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /serverless/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(serverless) 3 | 4 | test_check("serverless") 5 | -------------------------------------------------------------------------------- /serverless/tests/testthat/test_sample.R: -------------------------------------------------------------------------------- 1 | test_that("Sample Test",{ 2 | number <- 1 3 | expect_equal(1, number) 4 | }) 5 | --------------------------------------------------------------------------------