본 문서(node.js API 서비스 미터링 애플리케이션 개발 가이드)는 파스-타 플랫폼 프로젝트의 미터링 플러그인과 Node.js API 애플리케이션을 연동시켜 API 서비스를 미터링하는 방법에 대해 기술 하였다.
본 문서의 범위는 파스-타 플랫폼 프로젝트의 Node.js API 서비스 애플리케이션 개발과 CF-Abacus 연동에 대한 내용으로 한정되어 있다.
https://docs.cloudfoundry.org/devguide/ https://docs.cloudfoundry.org/buildpacks/node/node-tips.html https://nodejs.org/ http://expressjs.com/ko/ https://github.com/cloudfoundry-incubator/cf-abacus
API 서비스 및 해당 API 서비스를 사용하는 애플리케이션을 Node.js 언어로 작성 한다. API 서비스를 사용하는 애플리케이션과 API 서비스를 바인딩하고 해당 애플리케이션에 바인딩된 환경정보(VCAP_SERVICES)를 이용해 각 서비스별 접속정보를 획득하여 애플리케이션에 적용하여 API 서비스를 호출하는 애플리케이션을 작성 한다. 또한 API 서비스는 서비스 요청을 처리함과 동시에 API 사용 내역을 CF-ABACUS에 전송하는 애플리케이션을 작성 한다.
기능 | 설명 | |
Runtime | 미터링/등급/과금 정책 | API 서비스 제공자가 제공하는 서비스에 대한 각종 정책 정의 정보. JSON 형식으로 되었으며, 해당 정책을 CF-ABACUS에 등록하면 정책에 정의한 내용에 따라 API 사용량을 집계 한다. 정책은 서비스 제공자가 정의해야 하며, JSON 스키마는 다음을 참조한다. https://github.com/cloudfoundry-incubator/cf-abacus/blob/master/doc/api.md |
서비스 브로커 API | Cloud Controller와 Service Broker 사이의 규약으로써 서비스 브로커 API 개발에 대해서는 다음을 참조한다. https://github.com/OpenPaaSRnD/Documents/blob/master/Development-Guide/ServicePack_develope_guide.md#11 | |
서비스 API | 서비스 제공자가 제공하는 API 서비스 기능 및 API 사용량을 CF-ABACUS에 전송하는 기능으로 구성되었다. | |
대시보드 | 서비스를 제공하기 위한 인증, 서비스 모니터링 등을 위한 대시보드 기능으로 서비스 제공자가 개발해야 한다. | |
CF-ABACUS | CF-ABACUS 핵심 기능으로써 수집한 사용량 정보를 집계한다. CF-ABACUS은 CF 설치 후, CF에 마이크로 서비스 형태로 설치한다. 자세한 사항은 다음을 참조한다. https://github.com/cloudfoundry-incubator/cf-abacus | |
※ 본 개발 가이드는 API**서비스** 개발에 대해서만 기술하며, 다른 컴포넌트의 개발 또는 설치에 대해서 링크한 사이트를 참조한다.
Node.js 애플리케이션 개발을 위해 다음과 같은 환경으로 개발환경을 구성 한다.
CF release: v226 이상
nodejs_buildpack: nodejs_buildpack-cached-v1.5.18.zip 이상
Node.js: v5.11.1
npm: v3.8.6
$ sudo apt-get install curl## Node.js version 6.x를 설치할 경우## Source Repository 등록$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash –## Node.js & Npm 설치$ sudo apt-get install -y nodejs## Node.js & Nmp 설치 확인$ node -v$ npm -v
※ Windows 용은 다음 사이트에서 Node.js를 다운 받는다. https://nodejs.org/ko/download/
※ 개발도구 Node.js는 javascript기반의 언어로 Notepad++, Sublim Text, EditPlus등 문서편집기를 개발도구로 사용할 수 있다. 또한 Eclipse의 플러그인 Nodeclipse를 설치하여 사용할 수 있다. 그리고 상용 개발 도구로써는 WebStome 등이 있다.
별도 제공하는 Abacus 설치 가이드를 참고하여 CF-Abacus를 설치한다.
별도 제공하는 서비스 브로커 개발 가이드를 참고하여 서비스 브로커 및 대시보드를 개발한다. https://github.com/OpenPaaSRnD/Documents/blob/master/Development-Guide/ServicePack_develope_guide.md#6
샘플 api 서비스는 서비스 요청이 있는 경우, 해당 요청에 대한 응답 처리와 api 서비스 요청에 대한 미터링 정보를 CF-ABACUS에 전송하는 처리를 한다.
샘플 API 서비스 형상
sample_api_node_service/├── .apprc├── .gitignore├── manifest.yml├── .npmrc├── package.json├── sampleApiService└── src├── app.js└── test└── test.js
파일/폴더 | 목적 |
.apprc | 앱 실행 환경 설정 파일 |
.gitignore | Git을 통한 형상 관리 시, 형상 관리를 할 필요가 없는 파일 또는 디렉토리를 설정한다. |
manifest.yml | 애플리케이션을 파스-타 플랫폼에 배포 시 적용하는 애플리케이션에 대한 환경 설정 정보 애플리케이션의 이름, 배포 경로, 인스턴스 수 등을 정의할 수 있다. |
.npmrc | Npm 실행 환경 설정 파일 |
package.json | node.js 어플리케이션에 필요한 npm의 의존성 정보를 기술하는데 사용 한다. npm install 명령을 실행시 install 뒤에 아무런 정보를 입력하지 않으면 이 파일의 정보를 이용하여 npm을 설치한다. |
sampleApiService | 서비스 앱 실행 스크립트 |
app.js | 서비스 앱 서비스 요청에 대한 라우팅 정보와 미터링 정보 전송 처리를 정의한다. |
test.js | 서비스 앱 단위 테스트 모듈 mocha를 통한 서비스 앱의 단위 테스트를 정의한다. |
{"name": "sample-api-node-service", ## 앱 명"version": "0.0.1", ## 앱 버전"description": "CF API Usage Service Metering Sample","main": "lib/app.js", ## 개발 소스의 메인"bin": {"sampleApiService": "./sampleApiService"},"files": [ ## 형상 관리 대상의 파일 또는 디렉토리를 기술".apprc",".npmrc","manifest.yml","src/","sampleApiService"],"scripts": { ## npm run 명령어 또는 npm 명령어로 실행"start": "./sampleApiService start", ## npm start: 앱 실행"stop": "./sampleApiService stop", ## npm stop: 앱 중지"babel": "babel", ## npm run babel: 개발 소스를 컴파일"test": "eslint && mocha", ## npm test: 개발 소스를 테스트"lint": "eslint", ## npm run lint: 개발 소스 체크"pub": "publish", ## npm run publish: 개발 소스를 퍼블리시"cfpack": "cfpack", ## npm run cfpack: 컴파일한 개발 소스를 패키지화"cfpush": "cfpush" ## npm run cfpush: 패키지화 한 개발 소스를 cf에 push},"author": "PAASTA","license": "Apache-2.0", ## 라이선스 선언"dependencies": {"body-parser": "^1.15.2", ## json parser 모듈"cors": "^2.8.1", ## cross domain request 허용 모듈"express": "^4.14.0", ## node.js 웹 프레임워크"abacus-oauth": "^0.0.6-dev.8", ## Secured Abacus와 통신을 위한 Oauth 모듈"request": "^2.74.0", ## request 모듈"babel-preset-es2015": "^6.6.0", ## ECMA5를 ECMA6으로 변환하기 위한 모듈"commander": "^2.8.1", ## 명령어 실행 모듈"underscore": "^1.8.3" ## javascript에 사용할 수 있는 함수가 정의된 모듈},"devDependencies": { ## 개발 환경에서 의존하는 패키지"abacus-babel": "file:../../tools/babel", ## 개발 소스를 ECMA5 -> ECMA6으로 변환"abacus-cfpack": "file:../../tools/cfpack", ## 개발 소스를 cf에 push 할 수 있도록 패키지화 하는 패키지"abacus-cfpush": "file:../../tools/cfpush", ## 개발 소스를 cf에 push하는 패키지"abacus-coverage": "file:../../tools/coverage", ## 개발 소스에 대해 테스트 소스의 coverage율 체크 패키지"abacus-eslint": "file:../../tools/eslint", ## 개발 소스 코드 체크 패키지"abacus-mocha": "file:../../tools/mocha", ## mocha 테스트 실행 패키지"abacus-publish": "file:../../tools/publish" ## 개발 소스 퍼블리시 패키지},"engines": {"node": ">=5.11.1", ## nodejs 버전"npm": ">=3.8.6" ## npm 버전}}
applications:- name: sample-api-node-service # 애플리케이션 이름host: sample-api-node-service # 애플리케이션 호스트명memory: 512M # 애플리케이션 메모리 사이즈disk_quota: 512M # 애플리케이션 디스크 사이즈instances: 1 # 애플리케이션 인스턴스 개수command: npm start # CF에서의 애플리케이션 시작 명령어path: ./.cfpack/app.zip # 배포될 애플리케이션의 위치env:CONF: default # 명령어 실행 환경 설정 정보DEBUG: s* # 디버그 출력 대상 설정NODE_TLS_REJECT_UNAUTHORIZED: 0 # SSL flag offAPI: https://api.bosh-lite.com # CF API 서비스 엔드포인트COLLECTOR: https://localhost/v1/metering/collected/usage # api 사용량 전송 엔드포인드SECURED: true # Secured Abacus 설정: false or trueAUTH_SERVER: https://api.bosh-lite.com:443 # oauth 서비스 엔드포인트CLIENT_ID: abacus # oauth 권한 idCLIENT_SECRET: secret # oauth id 비밀번호JWTKEY: |+ # 앱을 secured mode로 서비스 하기 위해 유효성 체크를 위한 인증 서비스 공개키-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHFr+KICms+tuT1OXJwhCUmR2dKVy7psa8xzElSyzqx7oJyfJ1JZyOzToj9T5SfTIq396agbHJWVfYphNahvZ/7uMXqHxf+ZH9BL1gk9Y6kCnbM5R60gfwjyW1/dQPjOzn9N394zd2FJoFHwdq9Qs0wBugspULZVNRxq7veq/fzwIDAQAB-----END PUBLIC KEY-----JWTALGO: RS256
ENV 항목
아래에 기술한 항목 이외에 서비스에 필요한 항목을 추가할 수 있다.
ENV 항목 | 설명 |
DEBUG | 애플리케이션 디버그 로그 출력 대상 설정 |
NODE_TLS_REJECT_UNAUTHORIZED | - |
API | CF API URL https://api. |
COLLECTOR | Abacus Collector 앱의 사용량 수집 서비스 URL https:// /v1/metering/collected/usage |
SECURED | Secured abacus를 운용할 경우, 반드시 true를 설정한다. |
AUTH_SERVER | SECURED가 true인 경우 설정한다. - CF UAA를 Auth_server로 설정할 경우, https://api. - Abacus의 AuthServer를 Auth_server로 설정할 경우, abacus-authserver-plugin |
CLIENT_ID | SECURED가 true인 경우 설정한다. Abacus.usage 권한 id |
CLIENT_SECRET | SECURED가 true인 경우 설정한다. Abacus.usage 권한 비밀번호 |
JWTKEY | SECURED가 true인 경우 설정한다. - CF UAA를 Auth_server로 설정할 경우, CF 배포 manifest의 properties.jwt.verification_key 값을 설정 - Abacus의 AuthServer를 Auth_server로 설정할 경우, Key 값을 설정 |
JWTALGO | SECURED가 true인 경우 설정한다. - CF UAA를 Auth_server로 설정할 경우, RS256 - Abacus의 AuthServer를 Auth_server로 설정할 경우, HS256 |
의존 모듈 선언
'use strict';// Implemented in ES5 for now/* eslint no-var: 0 */ // ECMA5로 개발할 경우, eslint 체크에서 var 사용 제한을 풀어준다.var express = require('express'); // 웹 프레임워크 모듈var request = require('request'); // request 모듈var bodyParser = require('body-parser'); // request 정보를 json으로 변환하는 모듈var cp = require('child_process');var commander = require('commander'); // command 사용 가능 모듈var oauth = require('abacus-oauth'); // oauth 모듈
변수 선언
// Create routervar routes = express.Router(); // 앱 서비스 엔드포인트를 설정 할 미들웨어// Abacus Collector App's URLvar abacusCollectorUrl = process.env.COLLECTOR; // api 사용량 전송 url (abacus)// Abacus System Token Scopevar scope = 'abacus.usage.write abacus.usage.read'; // abacus를 secured로 설정할 경우, api 사용량 정보의 전송을 위한token scope 설정 (scope 설정에 대해서는 abacus 설치 가이드 참조)// 크로스 도메인 허용을 위한 헤더 설정var accessControlAllowHeader = 'Origin,X-Requested-With,Content-Type,Accept';// 아래의 항목은 더미로 설정한 미터링 대상 정보이다.// 실제 서비스를 구현할 경우, 해당 항목을 제공하는 API 호출이나 프로퍼티 값 등을 통해// 설정한다.var resourceId = 'object-storage';var measure1 = 'storage';var measure2 = 'light_api_calls';var measure3 = 'heavy_api_calls';var serviceKey = '[cloudfoundry]';
Secure Abacus 보안 구현
// abacus 토큰 초기화var abacusToken = void 0;// Secure 설정var secured = function secured() {return process.env.SECURED === 'true' ? true : false;};// abacus에 api usage를 전송할 때, request header 설정var authHeader = function authHeader(token) {return token ? { authorization: token() } : {};};… 중략 …var sampleApiService = function sampleApiService() {var app = express();// Secured abacue의 경우, 앱 서비스를 시작할 때, abacus 토큰을 구한다.if (secured()) {/*AUTH_SERVER: 인증 서버 엔드포인트 https://hostname:port orhttps://hostnameCLIENT_ID: 인증 서버 권한 아이디CLIENT_SECRET: 인증 서버 권한 비밀번호SCOPE: 토큰 scope*/abacusToken = oauth.cache(process.env.AUTH_SERVER, process.env.CLIENT_ID,process.env.CLIENT_SECRET, scope);// abacus Token을 주기적으로 갱신한다.abacusToken.start();};// api 서비스 또한 secured 모드로 실행 할 수 있다.// secured 모드로 실행할 경우, route에 등록한 모든 서비스에 대해 유효성 체크를 실행하도록 구현한다.// 본 샘플에서는 abacus의 oauth 서비스의 유효성 체크를 사용하였다.// if (secured())// app.use(/^\/plan[0-9]/,// oauth.validator(process.env.JWTKEY, process.env.JWTALGO));app.use(routes);return app;};… 후략 …
COR 설정
// api 서비스는 요청한 서비스의 응답 처리 이외에 abacus에 대해 request 처리가 추가로 필요하므로 크로스 도메인을 설정 한다.routes.use(function(req, res, next) {res.header('Access-Control-Allow-Origin', '*');res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');res.header('Access-Control-Allow-Headers', accessControlAllowHeader);next();});
서비스 API 구현
/*Sample API 'Plan1'1. Caller의 요청에 API 서비스를 처리 응답 (Sample에서는 생략)2. abacus에 api usage 전송*/routes.post('/plan1', function(req, res, next) {// api 요청 시각 설정var d = new Date();var eventTime = Date.parse(d);// 사용량 미터링에 필요한 메타 정보 설정var orgid = req.body.organization_id;var spaceid = req.body.space_id;var instanceid = reqs.body.instance_id ? reqs.body.instance_id : reqs.body.consumer_id;var appid = req.body.consumer_id;var planid = req.body.plan_id;var credential = req.body.credential;// 실제 서비스에 실행에 필요한 메타 정보는 inputs에 설정// var inputs = req.body.inputs;// 서비스 이용 권한 체크, 해당 체크 내용은 제공할 서비스에 맞게 변형한다.if (credential.serviceKey != serviceKey)return res.status(401).send();// 필수 항목 체크if (!orgid || !spaceid || !appid)return res.status(400).send();// abacus에 리포팅할 api 사용량 정보를 작성한다. (JSON 형식)var usage =buildAppUsage(orgid, spaceid, appid, instanceid, planid, eventTime);// api 사용량 정보 체크if (usage.usage === null) return res.status(400).send();// api 사용량 전송을 위한 요청 정보 설정var options = {uri: abacusCollectorUrl,headers: authHeader(abacusToken),json: usage.usage};// api usage를 abacus에 전송request.post(options, function(error, response, body) {// abacus 전송 처리 판정if (error) console.log(error);else if (response.statusCode === 201 || response.statusCode === 200) {// console.log('Successfully reported usage %j with headers %j',// usage, response.headers);res.status(201).send(response.body);return;}// abacus에 api 사용량을 중복 송신한 경우 발생else if (response.statusCode === 409) {// console.log('Conflicting usage %j. Response: %j',// usage, response);res.sendStatus(409);return;}// 기타 400 / 500 계열의 오류 체크else {// console.log('failed report usage %j with headers %j',// usage, response.headers);res.sendStatus(response.statusCode);return;}});return res;});
Abacus 전송 Json 생성
// abacus로 전송할 데이터 포맷을 만든다.var buildAppUsage =function buildAppUsage(orgid, spaceid, appid, insid, planid, eventTime) {var appUsage = { usage: null };// sample api plan id가 'standard'if (planid == 'standard')appUsage = {usage: {start: eventTime,end: eventTime,organization_id: orgid,space_id: spaceid,consumer_id: 'app:' + appid,resource_id: resourceId,plan_id: planid,resource_instance_id: insid,measured_usage: [{measure: measure1,quantity: 1073741824},{measure: measure2,quantity: 1000},{measure: measure3,quantity: 0}]}};return appUsage;};
기타
// 앱 서비스를 위한 설정 정보// PORT, HOST명 등을 설정한다.var conf = function conf() {process.env.PORT = commander.port || process.env.PORT || 9602;};// Command line 인터페이스 설정// package에 기술한 start, stop 스크립트를 실행할 수 있다.// 앱 시작: npm start// 앱 중지: npm stopvar runCLI = function runCLI() {commander.option('-p, --port <port>', 'port number [9602]').option('start', 'start the server').option('stop', 'stop the server').parse(process.argv);// Start API serverif (commander.start) {conf();// Create app and listen on the configured portvar app = sampleApiService();app.listen({port: parseInt(process.env.PORT)});}else if (commander.stop)// Stop API App servercp.exec('pkill -f "node ./sampleApiService"', function(err, stdout, stderr) {if (err) console.log('Stop error %o', err);});};// Export our public functionsmodule.exports = sampleApiService;module.exports.runCLI = runCLI
POST /v1/metering/collected/usage
항목명 | 유형 | 설명 | 예시 |
start | UNIX Timestamp | API처리 시작 시각 | 1396421450000 |
end | UNIX Timestamp | API처리 응답 시각 | 1396421451000 |
organization_id | String | API를 호출한 앱의 조직 ID | us-south:54257f98-83f0-4eca-ae04-9ea35277a538 |
space_id | String | API를 호출한 앱의 영역 ID | d98b5916-3c77-44b9-ac12-04456df23eae |
consumer_id | String | API를 호출한 앱 ID | App: d98b5916-3c77-44b9-ac12-04d61c7a4eae |
resource_id | String | API 자원 ID | sample_api |
plan_id | String | API 미터링 Plan ID | basic |
resource_instance_id | String | API를 호출한 앱 ID | d98b5916-3c77-44b9-ac12-04d61c7a4eae |
measured_usage | Array | 미터링 항목 | - |
measure | String | 미터링 대상 명 | api_calls |
quantity | Number | 해당 API 요청에 대한 API 처리 횟수 | 10 |
{"start": 1396421450000,"end": 1396421451000,"organization_id": "us-south:54257f98-83f0-4eca-ae04-9ea35277a538","space_id": "d98b5916-3c77-44b9-ac12-04456df23eae","consumer_id": "app:d98b5916-3c77-44b9-ac12-045678edabae","resource_id": "sample_api","plan_id": "basic","resource_instance_id": "d98b5916-3c77-44b9-ac12-04d61c7a4eae","measured_usage": [{"measure": "api_calls","quantity": 10}]}
참고: https://github.com/cloudfoundry-incubator/cf-abacus/blob/master/doc/api.md
Api 서비스를 이용하는 애플리케이션으로 본 샘플은 웹 화면을 통행 단순히 api 서비스를 요청하는 기능만을 구현 하였다.
sample_api_node_caller/├── .apprc├── cfpush.sh├── .eslintignore├── .gitignore├── manifest.yml├── .npmrc├── package.json├── sampleApiCaller├── src│ ├── app.js│ ├── bower_components│ └── test│ └── test.js└── views├── apiCaller.handlebars└── layouts└── main.handlebars
파일/폴더 | 목적 |
.apprc | 앱 실행 환경 설정 파일 |
cfpush.sh | Manifest의 org_id를 현재 target 설정된 org의 guid로 수정하고 패키지한 앱을 cf에 push 한다. |
.eslintignore | Eslint 실행 시, 체크 제외 대상의 파일 및 디렉토리를 설정한다. |
.gitignore | Git을 통한 형상 관리 시, 형상 관리를 할 필요가 없는 파일 또는 디렉토리를 설정한다. |
manifest.yml | 파스-타 플랫폼에 배포시 애플리케이션에 대한 설정이다. 애플리케이션의 이름, 배포 경로, 인스턴스 수 등을 정의할 수 있다. |
.npmrc | Npm 실행 환경 설정 파일 |
package.json | node.js 어플리케이션에 필요한 npm의 의존성 정보를 기술하는데 사용 한다. npm install 명령을 실행시 install 뒤에 아무런 정보를 입력하지 않으면 이 파일의 정보를 이용하여 npm을 설치한다. |
sampleApiCaller | 서비스 호출 앱 실행 스크립트 |
app.js | 서비스 호출 앱 웹 서비스 및 bind 한 api 서비스 호출에 대한 라우팅 정보를 정의한다. |
bower_components | 프론트엔드 라이브러리 디렉토리 |
test.js | 서비스 앱 단위 테스트 모듈 mocha를 통한 서비스 앱의 단위 테스트를 정의한다. |
views | 샘플 API 서비스 호출 데모 화면 |
샘플 애플리케이션의 코드 구성에 대해 기술한다.
{"name": "sample-api-node-caller","version": "0.0.1","description": "CF API Metering Caller Sample","main": "lib/app.js","bin": {"sampleApiCaller": "./sampleApiCaller"},"files": [".apprc",".eslintignore",".npmrc","cfpush.sh","manifest.yml","src/","views/"],"scripts": {"start": "./sampleApiCaller start","stop": "./sampleApiCaller stop","babel": "babel","test": "eslint && mocha","lint": "eslint","pub": "publish","cfpack": "cfpack","cfpush": "./cfpush.sh"},"author": "PAASTA","license": "Apache-2.0","dependencies": {"body-parser": "^1.15.2","cors": "^2.8.1","express": "^4.14.0","express-handlebars": "^3.0.0", ## 핸들러 모듈"babel-preset-es2015": "^6.6.0","request": "^2.74.0","commander": "^2.8.1","underscore": "^1.8.3"},"devDependencies": {"abacus-babel": "file:../../tools/babel","abacus-cfpack": "file:../../tools/cfpack","abacus-cfpush": "file:../../tools/cfpush","abacus-coverage": "file:../../tools/coverage","abacus-eslint": "file:../../tools/eslint","abacus-mocha": "file:../../tools/mocha","abacus-publish": "file:../../tools/publish"},"engines": {"node": ">=5.11.1","npm": ">=3.8.6"}}
앱을 CF에 배포할 때 필요한 설정 정보 및 앱 실행 환경에 필요한 설정 정보를 기술한다.
---applications:- name: sample-api-node-caller # 애플리케이션 이름memory: 512M # 애플리케이션 메모리 사이즈disk_quota: 512Minstances: 1 # 애플리케이션 인스턴스 개수path: ./.cfpack/app.zip # 배포될 애플리케이션의 위치command: npm start # CF에서의 애플리케이션 시작 명령어env:DEBUG: a*ORG_ID: d6ce3670-ab9c-4453-b993-f2821f54846bSECURED: false#AUTH_SERVER: https://api.bosh-lite.com:443#CLIENT_ID: abacus#CLIENT_SECRET: secret
ENV 항목
아래에 기술한 항목 이외에 서비스에 필요한 항목을 추가할 수 있다.
ENV 항목 | 설명 |
DEBUG | 애플리케이션 디버그 로그 출력 대상 설정 |
| |
ORG_ID | Caller 애플리케이션을 배포할 조직 ID |
| |
SECURED | API 서비스를 Secured로 운용할 경우, 반드시 true를 설정한다. |
| |
AUTH_SERVER | SECURED가 true인 경우 설정한다. - CF UAA를 Auth_server로 설정할 경우, https://api. - Abacus의 AuthServer를 Auth_server로 설정할 경우, abacus-authserver-plugin |
| |
CLIENT_ID | SECURED가 true인 경우 설정한다. Abacus.usage 권한 id |
| |
CLIENT_SECRET | SECURED가 true인 경우 설정한다.Abacus.usage 권한 비밀번호 |
| |
Api 서비스를 요청하는 애플리케이션을 구현한다.
의존 모듈 선언
'use strict';// Implemented in ES5 for now/* eslint no-var: 0 */var express = require('express');var request = require('request');var bodyParser = require('body-parser');var cp = require('child_process');var commander = require('commander');var handlebars = require('express-handlebars').create({ defaultLayout:'main' }); // 웹 서비스 뷰 처리 모듈
변수 선언
// 크로스 도메인 요청 헤더var accessControlAllowHeader = 'Origin,X-Requested-With,Content-Type,Accept';var vcapApp = undefined;var vcapService = undefined;var dummyOrgId = undefined;var vcapBindServices = undefined;// vcap_application 정보 설정vcapApp = JSON.parse(process.env.VCAP_APPLICATION);// vcap_service 정보 설정vcapService = JSON.parse(process.env.VCAP_SERVICES);// 조직 guid 설정dummyOrgId = process.env.ORG_ID;
Secure Abacus 보안 구현
// api 서비스를 참고 하여 api service 요청 시, header에 token을 설정하는 처리를 구현한다.
COR 설정
// api 서비스는 요청한 서비스의 응답 처리 이외에 abacus에 대해 request 처리가 추가로 필요하므로 크로스 도메인을 설정 한다.routes.use(function(req, res, next) {res.header('Access-Control-Allow-Origin', '*');res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');res.header('Access-Control-Allow-Headers', accessControlAllowHeader);next();});
서비스 API 구현
// VCAP_SERVICE에서 앱과 바인드한 서비스 정보를 가져온다.// 복수의 서비스가 앱에 바인드 될 수 있다.vcapBindServices = vcapService[Object.keys(vcapService)[0]];var sampleApiCaller = function sampleApiCaller() {var app = express();// 웹 서비스 뷰 처리app.engine('handlebars', handlebars.engine);app.set('view engine', 'handlebars');// 크로스 도메인 처리app.use(function(req, res, next) {res.header('Access-Control-Allow-Origin', '*');res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');res.header('Access-Control-Allow-Headers', accessControlAllowHeader);next();});// 뷰에서 참조하는 js 모듈을 미들웨어에 마운트 한다.app.use('/bower_components',express.static(__dirname + '/bower_components'));// 웹 서비스 메인을 미들웨어에 마운트 한다.app.get('/', function(req, res) {res.type('text/html');res.render('apiCaller'); // 뷰 생성});// to support JSON-encoded bodiesapp.use(bodyParser.json());// to support URL-encoded bodiesapp.use(bodyParser.urlencoded({extended: true}));/*Sample Web Service1. API 서비스를 요청*/app.post('/sampleApiSerivceCall', function(req, res, next) {// 앱에 Bind한 서비스가 없는 경우if (typeof vcapBindServices !== 'object') {return res.status(502).send('unbind service called');next();};// API Service와 연동 할 서비스를 구한다.// 바인드된 복수의 서비스 중에서 연동 할 서비스 정보를 구한다.var bindApiService = vcapBindServices[0];// 위에서 구한 서비스 정보에서 서비스 url를 구한다.var serviceUrl = bindApiService.credentials.uri ?bindApiService.credentials.uri : bindApiService.credentials.url;// API Service에 요청 할 JSON 을 작성한다.var callEvent = buildSendData(req.body, bindApiService);// Set request optionsvar options = {uri: serviceUrl,json: callEvent};// api Service에 요청하고 결과를 응답한다.request.post(options, function(error, response, body) {if (error) console.log(error);else if (response.statusCode === 201 || response.statusCode === 200) {// console.log('Successfully reported usage %j with headers %j',// usage, response.headers);res.status(201).send(response.body);return;}else {// console.log('failed report usage %j with headers %j',// usage, response.headers);res.sendStatus(response.statusCode);return;}});return res;});// Not foundapp.use(function(req, res) {res.type('text/plain');res.status(404);res.send('404 not found');});return app;};
Abacus 전송 Json 생성
// 서비스로 보낼 데이터를 JSON 형식으로 작성한다.var buildSendData = function buildSendData(args, bindApiService) {return {organization_id: dummyOrgId,space_id: vcapApp.space_id,consumer_id: vcapApp.application_id,instance_id: vcapApp.instance_id ?vcapApp.instance_id : vcapApp.application_id,plan_id: bindApiService.plan,credential: bindApiService.credentials,inputs: args};};
기타
// 앱 서비스를 위한 설정 정보// PORT, HOST명 등을 설정한다.var conf = function conf() {process.env.PORT = commander.port || process.env.PORT || 9601;};// Command line interfacevar runCLI = function runCLI() {commander.option('-p, --port <port>', 'port number [9601]').option('start', 'start the server').option('stop', 'stop the server').parse(process.argv);// Start Caller serverif (commander.start) {conf();// Create app and listen on the configured portvar app = sampleApiCaller();app.listen({port: parseInt(process.env.PORT)});}else if (commander.stop)// Stop Caller App servercp.exec('pkill -f "node ./sampleApiCaller"', function(err, stdout, stderr) {if (err) console.log('Stop error %o', err);});};// Export our public functionsmodule.exports = sampleApiCaller;module.exports.runCLI = runCLI;
Api 서비스를 요청하는 웹 화면
<!DOCTYPE html><html><head><meta charset="utf-8"><script src="bower_components/jquery/dist/jquery.min.js"></script><script type="text/javascript">$(document).ready(function() {$('#result_div').html('');var appUrl = document.URL;// 요청 서비스 입력 항목 설정var input_param1 = '서울';var input_param2 = '무교동';$('#send_btn').click(function(){$('#result_div').html('');var data = sendData( input_param1, input_param2 );$.ajax({url: appUrl + 'sampleApiSerivceCall',type:"POST",data:data,success:function(data){$('#result_div').html("posted.");},error:function(jqXHR,textStatus,errorThrown){$('#result_div').html(errorThrown);}});});});// 요청 서비스 입력 항목 설정, JSON 형식으로 작성한다.var sendData = function buildJSON( input_param1, input_param2 ) {return {input_param1: input_param1,input_param2: input_param2};};</script></head><body><form id="form"></form><h3>CF REMOTE SERVICE API CALL TEST</h3><button id="send_btn">SEND SERVICE API CALL</button><br><!--<h4>{{vcapService}}</h4>--></body></html>
GET|POST|PUT|DELETE <api_service_restful_api>
항목명 | 유형 | 설명 | 예시 |
org_id | String | API 서비스를 요청한 앱의 조직 ID | 54257f98-83f0-4eca-ae04-9ea35277a538 |
space_id | String | API 서비스를 요청한 앱의 영역 ID | d98b5916-3c77-44b9-ac12-04456df23eae |
consumer_id | String | API 서비스를 요청한 앱 ID | d98b5916-3c77-44b9-ac12-045678edabae |
instance_id | String | API 서비스를 요청한 앱의 자원 인스턴스 ID | d98b5916-3c77-44b9-ac12-045678edabad |
plan_id | String | 앱의 요청한 API 서비스의 plan ID | basic |
credentials | JSON | 서비스 요청에 필요한 credential 항목을 설정한다. | credentials: { key: value, … } |
inputs | JSON | 서비스 요청에 필요한 입력 정보를 설정한다. | inputs: { key: value,s ... } |
{organization_id: 'd6ce3670-ab9c-4453-b993-f2821f54846b',space_id: 'ab63eaed-7932-4f24-804d-dccb40a68752',consumer_id: 'ff7476f9-f5b6-420c-96f0-ac39be43de8c',instance_id: 'ff7476f9-f5b6-420c-96f0-ac39be43de8c',plan_id: 'standard',credential: {'serviceKey': '[cloudfoundry]','url': 'http://localhost:9602/plan1'},inputs: {key1: 'val1',key2: 'val2'}}
파스-타 플랫폼에 배포되는 애플리케이션이 바인딩된 서비스별 접속 정보를 얻기 위해서는 애플리케이션별로 등록되어있는 VCAP_SERVICES 환경설정 정보를 읽어들여 정보를 획득 할 수 있다.
서비스를 바인딩하면 JSON 형태로 환경설정 정보가 애플리케이션 별로 등록된다.
{"VCAP_SERVICES": {"sample_api_node_service": [{"credentials": {"documentUrl": "http://sample-api-node-service.bosh-lite.com/doc","serviceKey": "UxJWlzVP0VJquACPD+FohQ==","url": "http://sample-api-node-service.bosh-lite.com/"},"label": "sample_api_node_service","name": "sampleNodeApi","plan": "basic","provider": null,"syslog_drain_url": "PASTA_SERVICE_METERING","tags": ["Sample API Service"],"volume_mounts": []}]}}{"VCAP_APPLICATION": {"application_id": "58872d8a-edfc-44df-97f0-df67cf9033a7","application_name": "sample-api-node-caller","application_uris": ["sample-api-node-caller.bosh-lite.com"],"application_version": "55678102-584c-4fca-8304-82f727506b1d","limits": {"disk": 512,"fds": 16384,"mem": 512},"name": "sample-api-node-caller","space_id": "2ce08996-f463-406c-a971-adbbaf4e4ca5","space_name": "ops","uris": ["sample-api-node-caller.bosh-lite.com"],"users": null,"version": "55678102-584c-4fca-8304-82f727506b1d"}}
시스템 환경변수의 VCAP_SERVICES값을 읽어서 접근 할 수 있다.
process.env.VCAP_SERVICES
서비스, 그리고 서비스 제공자 마다 미터링/등급/과금 정책 다르기 때문에 본 가이드에서는 정책의 개발 예제를 다루지는 않는다. 다만 CF-ABACUS에 적용할 수 있는 형식에 대해 설명한다.
미터링 정책이란 수집한 미터링 정보에서 미터링 대상의 지정 및 집계 방식을 정의한 JSON 형식의 오브젝트이다. 서비스 제공자는 미터링 정책 스키마에 맞춰 서비스에 대한 정책을 개발한다.
항목명 | 유형 | 필수 | 설명 |
plan_id | String | O | API 미터링 Plan ID |
measures | Array | 최소 하나 | API 미터링 정보 수집 대상 정의 |
name | String | O | 미터링 정보 수집 대상 명 |
unit | String | O | 미터링 정보 수집 대상 단위 |
metrics | Array | 최소 하나 | API 미터링 집계 방식 정의 |
name | String | O | 미터링 정보 수집 대상 명 |
unit | String | O | 미터링 정보 수집 대상 단위 |
meter | String | X | 미터링 정보에 대해서 수집 단계에 적용하는 계산식 또는 변환식 |
accumulate | String | X | 미터링 정보에 대해서 누적 단계에 적용하는 계산식 또는 변환식 |
aggregate | String | X | 미터링 정보에 대해서 집계 단계에 적용하는 계산식 또는 변환식 |
summarize | String | X | 미터링 정보를 보고할 때 적용하는 계산식 또는 변환식 |
title | String | X | API 미터링 제목 |
{"plan_id": "basic-object-storage","measures": [{"name": "storage","unit": "BYTE"},{"name": "api_calls","units": "CALL"}],"metrics": [{"name": "storage","unit": "GIGABYTE","meter": "(m) => m.storage / 1073741824","accumulate": "(a, qty) => Math.max(a, qty)"},{"name": "thousand_api_calls","unit": "THOUSAND_CALLS","meter": "(m) => m.light_api_calls / 1000","accumulate": "(a, qty) => a ? a + qty : qty","aggregate": "(a, qty) => a ? a + qty : qty","summarize": "(t, qty) => qty"}]}
등급 정책이란 각 서비스의 사용 가중치를 정의한 JSON 형식의 오브젝트이다. 서비스 제공자는 등급 정책 스키마에 맞춰 서비스에 대한 정책을 개발한다.
항목명 | 유형 | 필수 | 설명 |
plan_id | String | O | API 등급 Plan ID |
metrics | Array | 최소 하나 | 등급 정책 목록 |
name | String | O | 등급 정의 대상 명 |
rate | String | X | 가중치 계산식 또는 변환식 |
charge | String | X | 사용량에 대한 과금 계산식 또는 변환식 |
title | String | X | 등급 정책 명 |
{"plan_id": "object-rating-plan","metrics": [{"name": "storage"},{"name": "thousand_api_calls","rate": "(p, qty) => p ? p * qty : 0","charge": "(t, cost) => cost"}]}
과금 정책이란 각 서비스에 대한 사용 단가를 정의한 JSON 형식의 오브젝트이다. 서비스 제공자는 과금 정책 스키마에 맞춰 서비스에 대한 정책을 개발한다.
항목명 | 유형 | 필수 | 설명 |
plan_id | String | O | API 과금 Plan ID |
metrics | Array | 최소 하나 | 과금 정책 목록 |
name | String | O | 과금 대상 명 |
price | Array | 최소 하나 | 과금 정책 상세 |
country | String | O | 서비스 사용 단가에 적용할 통화 |
price | Number | O | 서비스 사용 단가 |
title | String | X | 과금 정책 제목 |
{"plan_id": "object-pricing-basic","metrics": [{"name": "storage","prices": [{"country": "USA","price": 1},{"country": "EUR","price": 0.7523},{"country": "CAN","price": 1.06}]},{"name": "thousand_api_calls","prices": [{"country": "USA","price": 0.03},{"country": "EUR","price": 0.0226},{"country": "CAN","price": 0.0317}]}]}
정책은 2가지 방식 중 하나의 방법으로 CF-ABACUS에 등록할 수 있다.
작성한 정책을 다음의 디렉토리에 저장한 후, CF에 CF-ABACUS를 배포 또는 재배포 한다.
미터링 정책의 경우
cf-abacus/lib/plugins/provisioning/src/plans/metering
등급 정책의 경우
cf-abacus/lib/plugins/provisioning/src/plans/pricing
과금 정책의 경우
cf-abacus/lib/plugins/provisioning/src/plans/rating
작성한 정책을 curl 등을 이용해 DB에 저장하는 방식으로 CF-ABACUS를 재배포할 필요는 없다. 정책 등록 시, 정책 ID는 고유해야 한다.
미터링 정책의 경우
POST /v1/metering/plans/:metering_plan_id
>
$ curl -k -X POST 'http://abacus-provisioning-plugin.bosh-lite.com/v1/metering/plans/sample-linux-container' \-H "Content-Type: application/json" \-d '{"plan_id":"sample-linux-container","measures":[{"name":"current_instance_memory","unit":"GIGABYTE"},{"name":"current_running_instances","unit":"NUMBER"},{"name":"previous_instance_memory","unit":"GIGABYTE"},{"name":"previous_running_instances","unit":"NUMBER"}],"metrics":[{"name":"memory","unit":"GIGABYTE","type":"time-based","meter":"((m)=>({previous_consuming:newBigNumber(m.previous_instance_memory||0).div(1073741824).mul(m.previous_running_instances||0).mul(-1).toNumber(),consuming:newBigNumber(m.current_instance_memory||0).div(1073741824).mul(m.current_running_instances||0).toNumber()})).toString()","accumulate":"((a,qty,start,end,from,to,twCell)=>{if(end<from||end>=to)returnnull;constpast=from-start;constfuture=to-start;consttd=past+future;return{consuming:a&&a.since>start?a.consuming:qty.consuming,consumed:newBigNumber(qty.consuming).mul(td).add(newBigNumber(qty.previous_consuming).mul(td)).add(a?a.consumed:0).toNumber(),since:a&&a.since>start?a.since:start};}).toString()","aggregate":"((a,prev,curr,aggTwCell,accTwCell)=>{if(!curr)returna;constconsuming=newBigNumber(curr.consuming).sub(prev?prev.consuming:0);constconsumed=newBigNumber(curr.consumed).sub(prev?prev.consumed:0);return{consuming:consuming.add(a?a.consuming:0).toNumber(),consumed:consumed.add(a?a.consumed:0).toNumber()};}).toString()","summarize":"((t,qty,from,to)=>{if(!qty)return0;constrt=Math.min(t,to?to:t);constpast=from-rt;constfuture=to-rt;consttd=past+future;constconsumed=newBigNumber(qty.consuming).mul(-1).mul(td).toNumber();returnnewBigNumber(qty.consumed).add(consumed).div(2).div(3600000).toNumber();}).toString()"}]}' \-H "Authorization: $(cf oauth-token | grep bearer)"
등급 정책의 경우
POST /v1/rating/plans/:rating_plan_id
>
# 예제$ curl -k -X POST 'http://abacus-provisioning-plugin.bosh-lite.com/v1/rating/plans/linux-rating-sample' \-H "Content-Type: application/json" \-d '{"plan_id":"linux-rating-sample","metrics":[{"name":"memory","rate":"((price,qty)=>({price:price,consuming:qty.consuming,consumed:qty.consumed})).toString(),charge:((t,qty,from,to)=>{if(!qty)return0;constrt=Math.min(t,to?to:t);constpast=from-rt;constfuture=to-rt;consttd=past+future;constconsumed=newBigNumber(qty.consuming).mul(-1).mul(td).toNumber();constgbhour=newBigNumber(qty.consumed).add(consumed).div(2).div(3600000).toNumber();returnnewBigNumber(gbhour).mul(qty.price).toNumber();}).toString()"}]}' \-H "Authorization: $(cf oauth-token | grep bearer)"
과금 정책의 경우
POST /v1/pricing/plans/:pricing_plan_id
>
# 예제$ curl -k -X POST 'http://abacus-provisioning-plugin.bosh-lite.com/v1/pricing/plans/linux-pricing-sample' \-H "Content-Type: application/json" \-d '{"plan_id":"linux-pricing-sample","metrics":[{"name":"memory","prices":[{"country":"USA","price":0.00014}]}]}' \-H "Authorization: $(cf oauth-token | grep bearer)"
파스-타 플랫폼에 애플리케이션을 배포하면 배포한 애플리케이션과 파스-타 플랫폼이 제공하는 서비스를 연결하여 사용할 수 있다. 파스-타 플랫폼상에서 실행을 해야만 파스-타 플랫폼의 애플리케이션 환경변수에 접근하여 서비스에 접속할 수 있다.
아래의 과정을 수행하기 위해서 파스-타 플랫폼에 로그인
$ cf api --skip-ssl-validation https://api.<파스-타 도메인> # 파스-타 플랫폼 TARGET 지정$ cf login -u <user name> -o <org name> -s <space name> # 로그인 요청
애플리케이션에서 사용할 서비스를 파스-타 플랫폼을 통하여 생성한다. 별도의 서비스 설치과정 없이 생성할 수 있으며, 애플리케이션과 바인딩과정을 통해 접속정보를 얻을 수있다.
서비스 생성 (cf marketplace 명령을 통해 서비스 목록과 각 서비스의 플랜을 조회할 수 있다.)
Gradle 버전: 2.2
## 서비스 브로커 CF 배포$ cd <샘플 서비스 브로커 경로>/sample_api_java_broker$ gradle build -x test:compileJavaNote: ~/PAASTA-API-METERING-SAMPLE/lib/sample_api_java_broker/src/main/java/org/openpaas/servicebroker/api/config/CatalogConfig.java uses unchecked or unsafe operations.Note: Recompile with -Xlint:unchecked for details.:processResources:classes:findMainClass:jar:bootRepackage:assemble:check:buildBUILD SUCCESSFULTotal time: 28.905 secsThis build could be faster, please consider using the Gradle Daemon: https://docs.gradle.org/2.14.1/userguide/gradle_daemon.html$ cf push## 서비스 브로커 생성$ cf create-service-broker <서비스 브로커 명> <인증ID> <인증Password> <서비스 브로커 주소>예)$ cf create-service-broker sample-api-broker admin cloudfoundry http://sample-api-java-broker.bosh-lite.com## 서비스 브로커 확인$ cf service-brokersGetting service brokers as admin...name urlsample-api-broker http://sample-api-java-broker.bosh-lite.com## 서비스 카탈로그 확인$ cf service-accessGetting service access as admin...broker: sample-api-brokerservice plan access orgsstandard_obejct_storage_light_api_calls standard nonestandard_obejct_storage_heavy_api_calls basic none## 등록한 서비스 접근 허용$ cf enable-service-access <서비스명> -p <플랜명>예)$ cf enable-service-access standard_obejct_storage_light_api_calls -p standard
API 서비스 애플리케이션을 파스-타 플랫폼에 배포한다. 서비스 등록한 API는 다른 애플리케이션과 바인드하여 API 서비스를 할 수 있다.
cf push 명령으로 배포한다. 별도의 값을 넣지않으면 manifest.yml의 설정을 사용한다.
## API 서비스 배포$ cd <샘플 api 서비스 경로>/sample_api_node_service$ npm install && npm run babel && npm run cfpack && cf push## 서비스 생성$ cf create-service <서비스명> <플랜명> <서비스 인스턴스명>예)$ cf create-service standard_obejct_storage_light_api_calls standard sampleNodejslightCallApi## 서비스 확인$ cf servicesGetting services in org real / space ops as admin...OKname service plan bound apps last operationsampleNodejslightCallApi standard_obejct_storage_light_api_calls standard create succeeded
애플리케이션과 서비스를 연결하는 과정을 '바인드(bind)라고 하며, 이 과정을 통해 서비스에 접근할 수 있는 접속정보를 생성한다.
애플리케이션과 서비스 연결
## API 서비스 연동 샘플 애플리케이션 배포$ cd <샘플 애플리케이션 경로>/sample_api_node_caller$ npm install && npm run babel && npm run cfpack && ./cfpush.sh## 서비스 바인드$ cf bind-service <APP_NAME> <SERVICE_INSTANCE> -c <PARAMETERS_AS_JSON>예)$ cf bind-service sample-api-node-caller sampleNodejslightCallApi -c '{"serviceKey": "[cloudfoundry]"}'## 서비스 연결 확인$ cf servicesGetting services in org real / space ops as admin...OKname service plan bound apps last operationsampleNodejslightCallApi standard_obejct_storage_light_api_calls standard sample-api-node-caller create succeeded## 애플리케이션 실행$ cf start <APP_NAME>예)$ cf start sample-api-node-caller## 형상 확인$ cf aGetting apps in org real / space ops as admin...OKname requested state instances memory disk urlssample-api-node-service started 1/1 512M 512M sample-api-node-service.bosh-lite.comsample-api-java-broker started 1/1 512M 1G sample-api-java-broker.bosh-lite.comsample-api-node-caller started 1/1 512M 512M sample-api-node-caller.bosh-lite.com
샘플 애플리케이션은 REST 서비스로 구현되어 있으며, 코드 체크, 테스트 및 커버리스 체크를 위해서 eslint/mocha/Istanbul 모듈을 사용하였다. 테스트를 진행하기 위해서는 mocha 모듈을 포함한 package.json 안의 devDependencies모듈이 설치 되어 있어야한다. (npm install)
테스트를 위한 형상
<앱>/├── .eslint // 코드 체크 대상 설정├── .eslintignore // 코드 체크에서 제외할 파일 또는 디렉토리 정의├── package.json // 앱 구성 요소 정의├── lib // npm run babel을 실행하면 자동으로 생성된다. cfpack 및 mocha 테스트 는 lib에 있는 모듈을 대상 한다.│ ├── app.js // ECMA5로 변환된 app.js│ ├── bower_components│ └── test│ └── test.js├── src // 코드 변환 및 코드 체크 대상 디렉토리│ ├── app.js│ ├── bower_components│ └── test // mocha 테스트 모듈은 반드시 src/test 디렉토리에 있어야 한다.│ └── test.js└── views // src/lib 이외에 위치한 디렉토리와 파일은 체크 및 mocha 테스트 대상이 아니다.├── apiCaller.handlebars└── layouts└── main.handlebars
테스트를 위한 package.json 구성
{... 중략"scripts": {"babel": "babel", // 코드 변환"test": "eslint && mocha", // 코드 체크 및 테스트"lint": "eslint" // 코드 체크},... 중략"devDependencies": {"abacus-babel": "^0.0.6-dev.8", // 코드 변환 (ECMA6 -> ECMA5)"abacus-coverage": "^0.0.6-dev.8", // 테스트 커버리지 체크"abacus-eslint": "^0.0.6-dev.8", // 코드 체크"abacus-mocha": "^0.0.6-dev.8" // 코드 테스트},... 후략}
Eslint 설정
// false / 0 / disable을 설정한 항목에 대해서만 체크를 생략한다.// 규칙에 대한 자세한 내용은 http://eslint.org/docs/rules/ 을 참고 한다.---parser: espreeenv:browser: truenode: truees6: falsejasmine: truemocha: trueglobals:__DEV__: truejest: truesinon: truechai: truespy: truestub: trueparserOptions:sourceType: "module"rules:# ERRORSspace-before-blocks: 2 // 공백 문자가 2개 이상 연속indent: [2, 2, { "SwitchCase": 1 }] // 들여쓰기 형식 설정 (공백문자 2개만 허용)#strict: [2, "global"]semi: [2, "always"] // ‘;’ 누락comma-dangle: [2, "never"]no-unused-expressions: 2block-scoped-var: 2dot-notation: 2consistent-return: 2 // 함수의 응답 결과 형식 불일치no-unused-vars: [2, args: none] // 소스내 참조되지 않는 변수 선언quotes: [2, 'single'] // 문자열에 ‘“’ 사용 금지space-infix-ops: 2no-else-return: 2no-extra-parens: 2no-eq-null: 2no-floating-decimal: 2no-param-reassign: 2no-self-compare: 2wrap-iife: [2, "inside"]brace-style: [2, "stroustrup", { "allowSingleLine": false }]object-curly-spacing: [1, "always"]func-style: [2, "expression"]no-lonely-if: 2space-in-parens: [2, "never"]space-before-function-paren: [2, "never"]generator-star-spacing: [2, "before"]spaced-comment: [2, "always"]eol-last: 2 // 소스 코드의 마지막에 개행문자 없음no-multi-spaces: 2curly: [2, "multi"]camelcase: [2, {properties: "never"}] // 변수명에 ‘_’ 사용 허용no-eval: 2#require-yield: 2no-var: 2 // 변수 선언에 var 금지 (ECMA6)max-len: [2, 80] // 한줄에 80자까지 허용complexity: [2, 6]arrow-parens: [2, "always"]# WARNINGS# We use this for functions that reference each otherno-use-before-define: 1# WISHLIST.# valid-jsdoc: 1# DISABLED. These aren't compatible with our style# We use this for private/internal variablesno-underscore-dangle: 0# We pass constructors around / access them from membersnew-cap: 0# We do this in a few places to align valueskey-spacing: 0# We do this a lotspace-after-keywords: 0# We do this mostly for callbacksno-shadow: 0# We do not use spaces in brackets but use spaces in bracesspace-in-brackets: 0
Test 디렉토리 아래에 있는 모듈을 테스트 한다.
$ cd <샘플 애플리케이션 경로>/<앱>$ npm install && npm run babel && npm test$ npm install && npm run babel && npm testsample-api-node-service@0.0.1 ~/PAASTA-API-METERING-SAMPLE/lib/sample_api_node_service├─┬ abacus-babel@0.0.6-dev.8... 설치 패키지 트리 출력 ...npm WARN sample-api-node-service@0.0.1 No repository field.> sample-api-node-service@0.0.1 babel /home/cloud4u/workspace/PAASTA-API-METERING-SAMPLE/lib/sample_api_node_service> babelsrc/app.js -> lib/app.jssrc/test/test.js -> lib/test/test.js> sample-api-node-service@0.0.1 test /home/cloud4u/workspace/PAASTA-API-METERING-SAMPLE/lib/sample_api_node_service> eslint && mocha
Testing...Running Istanbul instrumentation on node_modules/abacus-oauth/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-request/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-transform/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-yieldable/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-debug/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-events/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-lock/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-lrucache/lib/index.jsRunning Istanbul instrumentation on node_modules/abacus-retry/lib/index.jssample-api-node-serviceRunning Istanbul instrumentation on lib/app.js✓ Send API usage data to Abacus (59ms)✓ Missing metering parameter✓ Not serviced plan✓ Missing credentials✓ Send duplicated data to Abacus✓ Abacus is not serviced6 passing (159ms)Source lib/app.js'use strict';// Implemented in ES5 for now/* eslint no-var: 0 */... 중략 ...// Export our public functionsmodule.exports = sampleApiService;module.exports.runCLI = runCLI;Coverage lines 88.89% statements 86.9% lib/app.jsRun time 686ms
API 연동 샘플 애플리케이션의 url을 통해 웹 브라우저에서 접속하면 API 연동 및 API 사용량에 대한 CF-Abacus 연동 테스트를 진행 할 수 있다.
## 조직 guid 확인$ cf org <샘플 애플리케이션을 배포한 조직> --guid예)$ cf org real --guid877d01b2-d177-4209-95b0-00de794d9bba## 샘플 애플리케이션 guid 확인$ cf env <샘플 애플리케이션 명>예)$ cf env sample-api-node-callerGetting env variables for app sample-api-node-caller in org real / space ops as admin...OK<<중략>>{"VCAP_APPLICATION": {"application_id": "58872d8a-edfc-44df-97f0-df67cf9033a7","application_name": "sample-api-node-caller","application_uris": ["sample-api-node-caller.bosh-lite.com"],"application_version": "55678102-584c-4fca-8304-82f727506b1d","limits": {"disk": 512,"fds": 16384,"mem": 512},"name": "sample-api-node-caller","space_id": "2ce08996-f463-406c-a971-adbbaf4e4ca5","space_name": "ops","uris": ["sample-api-node-caller.bosh-lite.com"],"users": null,"version": "55678102-584c-4fca-8304-82f727506b1d"}}<<후략>>## API 사용량 확인$ curl 'http://abacus-usage-reporting.<파스-타 도메인>/v1/metering/organizations/<샘플 애플리케이션을 배포한 조직>/aggregated/usage'예)$ curl 'http://abacus-usage-reporting.bosh-lite.com/v1/metering/organizations/877d01b2-d177-4209-95b0-00de794d9bba/aggregated/usage'
샘플코드는 아래의 사이트에 다운로드 할 수 있다.
다운로드