본 문서(Java 서비스브로커 미터링 애플리케이션 개발 가이드)는 파스-타 플랫폼 프로젝트의 서비스 브로커에 미터링 서비스를 추가하여, CF(Cloud Foundry) 서비스를 미터링 하는 방법에 대해 기술 한다.
1.1.2. 범위
본 문서의 범위는 파스-타 플랫폼 프로젝트의 Cloud Foundry JAVA 서비스 브로커 애플리케이션 미터링 개발과 CF-Abacus 연동에 대한 내용으로 한정되어 있다. 서비스브로커 API 개발에 대해서는 별도 제공 하는 서비스브로커 API 개발 가이드를 참고 한다.
본 문서는 Ubuntu 14.04 ver의 개발 환경을 전제로 기술 한다.
본 문서는 mongo-db 서비스 팩이 설치 되어 있는 개발 환경을 전제로 기술 한다.
mongo-db 서비스 팩 설치는 별로 로 제공 되는 문서를 참고 하여 설치 한다.
본 문서는 cf-abacus 가 설치 되어 있는 개발 환경을 전제로 기술 한다. (cf-abacus 설치는 별도 제공하는 Abacus 설치 가이드를 참고하여 CF-Abacus를 설치한다.)
1.3. 참고 자료
2. Java서비스 미터링 개발가이드
2.1. 개요
CF Services 는 Service Broker API 라고 불리우는 cloud controller 클라이언트 API를 구현하여 개방형 클라우드 플랫폼에서 사용된다. Services API는 독립적인 cloud controller API의 버전이다. 이는 플랫폼에서 외부 application을 이용 가능하게 한다. (database, message queue, rest endpoint, etc.)
개방형 클라우드 플랫폼 Service API는 Cloud Controller 와 Service Broker 사이의 규약 (catalog, provision, de provision, update provision plan, bind, unbind)이고 Service Broker 는 RESTful API 로 구현하고 Cloud Controller 에 등록한다.
서비스에 미터링 구현하고자 할 때, 이 규약들 중 서비스 정책 및 취지에 맞는 프로세스를 선택하여, 그 프로세스에 미터링을 연동할 수 있다.
본 개발가이드에서는 mongo-db 서비스를 예시로, bind 와 unbind 시 미터링을 하는 방법에 대해 가이드 한다.
서비스를 사용하고자 하는 애플리케이션과 API 서비스를 바인딩 할 때, CF CLI 바인딩 요청 request에 적용 된 애플리케이션 환경정보(org guid, space guid, app guid, metering plan id) 를 이용해 바인딩 정보를 획득 하여, 서비스 요청을 처리함과 동시에 서비스의 사용 내역을 CF-ABACUS에 전송하는 미터링 서비스 기능을 mongo-db 서비스 브로커에 추가하여 개발 한다.
Service Broker API Architecture
기능
설명
Runtime
미터링/등급/과금 정책
서비스 브로커 API
Cloud Controller와 Service 사이에서 서비스의 create, delete, update, bind, unbind를 처리한다. 본문서에서는 mongo-db 서비스 브로커 API를 대상으로 미터링 서비스를 개발 하여 추가 한다.
서비스 브로커
미터링 서비스
서비스 브로커 API 가 abacus-usage-collector 에 서비스 사용량 정보를 전송하는 서비스 (본 문서에서 가이드 할 개발 영역 이다)
서비스
서비스 제공자가 제공하는 서비스 기능
CF-ABACUS
※ 본 개발 가이드는 애플리케이션과 서비스가 바인드 되는 시점을 서비스의 이용 시작으로 판단할 수 있는 서비스에 대해 미터링 하는 기능 개발에 대해서만 기술한다.
※ 서비스의 특정 API 호출 , 서비스의 특정 자원 이용 등에 대한 미터링 기능 개발에 대해서는 기술하지 않는다. ※ API 호출에 대한 미터링은 API 서비스 미터링 개발 가이드를 참조한다.
CF (개방형 플랫폼) 에서는 플랫폼 상에서 서비스 할 수 있는 다양한 서비스들이 존재한다.
이 서비스들은 각각 그 서비스 고유의 서비스 브로커를 개발 함으로써, CF (개방형 플랫폼) 에서 애플리케이션이 서비스를 사용 할 수 있도록 하고 있다.
서비스는 다양하지만, 서비스를 사용하기 위한 개방형 플랫폼의 RESTAPI가 미리 정해져 있다.
서비스 브로커 라이브러리는 각각 다른 서비스 브로커들이 서비스 브로커 라이브러리 Jar 파일을 build path 에 추가 하고, 추상화 클래스들을 구현 하는 것으로 이 개방형 플랫폼의 REST API에 기반 하여, 서비스가 제공 될 수 있도록 해주는 라이브러리 이다.
본 가이드에서는 mongo-db 서비스 브로커에 미터링 서비스를 구현하기 위해서는 이 서비스 브로커 라이브러리에 미터링을 하기 위한 추상화 클래스를 추가 한 후, mongo-db 서비스 브로커에서 이 라이브러리를 dependency로 사용하여 빌드 한다.
다운 받은 소스를 Java 개발 도구 Eclipse 및 Spring Tool Suite 로 import 한다.
gradle 플러그인을 Eclipse 에 추가한 후, gradle import 하면 개발이 보다 용이 해진다.
2.3.3. 서비스 브로커 라이브러리에서 미터링을 위해 추가 되거나 수정 되는 파일들
Java class
설명
수정
ServiceIncetanceBindingController
클라우드 컨트롤러의 서비스 바인딩 요청을 처리하는 컨트롤러,
SampleMeteringOAuthService 에서 uaa token 을 취득하여, SampleMeteringReportService 의 파라메터로 호출 하는 프로세스를 추가 한다.
수정
ServiceInstanceBinding
service-binding-request 가 ServiceIncetanceBindingController 에서 처리 될 때 바인딩 연결에 대해 미터링이 적용된 사용량 보고서를 abacus-usage-collector 에 리포팅 한다.
추가
SampleMeteringReportService
SampleMeteringReportService 추상화 된 인터페이스로서, 미터링/등급/과금 정책과 관련된 그 어떠한 정보도 가지고 있지 않다. 이는 이 인터페이스를 구현할 서비스 제공자가 서비스 구현체에 적용할 수 있도록 제공되고 있는 추상화 클래스 이다.
SampleMeteringReportService 추상화 된 인터페이스로서, 미터링/등급/과금 정책과 관련된 그 어떠한 정보도 가지고 있지 않다. 이는 이 인터페이스를 구현할 서비스 제공자가 서비스 구현체에 적용할 수 있도록 제공되고 있는 추상화 클래스 이다.
추가
SampleMeteringOAuthService
개방형 플랫폼 상의 UAA 서버에서 abacus-usage-collector 에 대한 접근 권한 토큰을 취득하여, SampleMeteringReportService 에 토큰을 전달 하기 위한 추상화 클래스 이다.
서비스 브로커 라이브러리에서 미터링을 위해 추가 되거나 수정 되는 파일의 형상
2.3.4. ServiceInstanceBindingController
bindServiceInstance 프로세스 에 SampleMeteringOAuthService 에서 uaa token 을 취득하여, SampleMeteringReportService 의 파라메터로 호출 하는 프로세스를 추가 한다.
ServiceInstanceBinding 에 미터링 서비스를 구현하기 위해 바인딩 되는 애플리케이션의 환경 정보 필드를 추가 한다. 추가 된 필드 들은 ServiceInstanceBindingService 의 구현체 에서 서비스 바인딩 request parameter 의 필드 값들을 매핑 처리 한 후, mongo-db repository 에 전달될 것이다. 라이브러리를 gradle build 한다.
UAA OAuthToken은 Abacus가 Secured로 운영될 경우, abucus-collector RESTAPI에 접근 하기 위해 필요하다.
SampleMeteringOAuthService를 상속하는 클래스는 UAA OAuthToken을 취득하여 리턴하는 처리를 구현해야 한다.
SampleMeteringReportService를 상속하는 클래스는 create binding request와 delete binding request를 처리 할 때, 각각 해당 이벤트 정보를 abacus-collector에 전송하고 해당 처리에 대한 상태코드(HTTP 상태코드)를 리턴하는 처리를 구현해야 한다.
package org.openpaas.servicebroker.service;
import org.openpaas.servicebroker.exception.ServiceBrokerException;
import org.openpaas.servicebroker.model.ServiceInstanceBinding;
public interface SampleMeteringReportService {
int reportServiceInstanceBinding(ServiceInstanceBinding serviceInstanceBinding,
String uaaToken)
throws ServiceBrokerException;
int reportServiceInstanceBindingDelete(ServiceInstanceBinding serviceInstanceBinding,
String uaaToken)
throws ServiceBrokerException;
}
2.4. 서비스 브로커 라이브러리
2.4.1. mongo-db 서비스 브로커 API
지금까지 서비스 브로커 라이브러리를 개수 하여, 미터링을 위한 추상화 클래스 및 모델 객체들을 준비 했다. 지금 부터는 서비스 브로커 라이브러리를 구현한 mongo-db 서비스 브로커 API에서 미터링을 구현 하는 것에 대해 기술 한다.
2.4.2. mongo-db 서비스 브로커 API 다운로드
mongo-db 서비스 브로커 API는 별도 제공되는 압축 파일 패키지를 사용한다.
2.4.3. mongo-db 서비스 브로커 API에 추가 및 수정 되는 파일
유형
필수
수정
build.gradle
빌드 설정 파일
미터링 사용량 객체 생성에 필요한 dependency 를 추가 한다.
수정
application-mvc.properties
서비스 바인딩 request 의 정보들을 매핑한다.
미터링 서비스를 구현하기 위해 바인딩 되는 애플리케이션의 환경정보 필드를 추가 한다.
수정
datasource.properties
Mongo-db 서비스 정보
수정
MongoServiceInstanceBindingService
service broker binding request parameter 로 입력 받은 미터링 정보를 ServiceInstanceBinding 에 매핑하는 프로세스를 추가 한다.
추가
SampleMeteringReportServiceImpl
SampleMeteringReportService 를 구현 한다.
추가
SampleMeteringOAuthServiceImpl
SampleMeteringOAuthService 를 구현 한다.
수정
Manifest.yml
앱을 CF에 배포할 때 필요한 설정 정보 및 앱 실행 환경에 필요한 설정 정보를 기술한다.
# abacus usage collector RESTAPI 의 주소
abacus.collector: https://abacus-usage-collector.<파스-타 도메인> /v1/metering/collected/usage
# abacus usage collector 가 secured 모드 true / 아닐 경우 false
abacus.secured: true
# 개발형 플랫폼의 uaa server
uaa.server: https://uaa.<파스-타 도메인>
# abacus usage collector RESTAPI 사용권한 (UAA server 에 미리 등록한다.)
uaa.client.id: abacus-linux-container
uaa.client.secret: secret
uaa.client.scope: abacus.usage.linux-container.write,abacus.usage.linux-container.read
uaa 계정 설정 방법에 관해서 별도의 abacus**설치 가이드의 Secured Abacus를 위한UAA**계정 등록을 참고한다.
SampleMeteringReportServiceImpl에서는 SampleMeteringOAuthServiceImpl에서 취득한 uaa token 으로 https 커넥션을 생성하여, abacus-collector에 서비스 사용량 정보를 POST 한다.
abacus-collector 에서는 미터링 정책에 따라 POST 받을 양식에 대한 프로세스를 준비 하고 있기 때문에 abacus-collector가 알 수 있는 양식으로 JSON을 생성 후 POST 한다.
SampleMeteringReportServiceImpl 은 크게 나누어 2가지 처리를 하고 있다.
1. ServiceInstanceBinding 정보를 참조 하여 ,사용량 정보 JSON을 생성 한다.
2. 생성한 사용량 정보 JSON을 abacus-collector로 전송한다. (HTTPS, HTTP)
사용량 정보 JSON 을 생성 한다.
RESOURCE_ID linux-container 와 STANDARD_PLAN_ID standard 는 abacus에서 sample 로 제공 되는 미터링 스키마이다.
본 가이드에서는 이 미터링 스키마를 mongo-db 서비스 바인딩과 언바인딩에 대한 미터링 스키마로 이용하여 기술 했다.
서비스 제공자는 제공 하려는 서비스에 맞는 정책을 정하여, 미터링 스키마를 abacus-프로비저닝에 등록 해야, abacus-collector 에 미터링을 전송할 수 있게 된다. (정책 등록에 대한 자세한 내용은 본문 하기의 미터링/과금 정책 참조)
다음 예제의 미터링 리포팅 용 상수들은 abacus의 linux-container 미터링 스키마에 맞게 기술 되었고, PLAN_STANDARD_QUANTITY, PLAN_EXTRA_QUANTITY 등은 임의로 정한 수치 이다. 서비스에 맞게 해당 항목을 DB 또는 프로퍼티 등을 통해 설정한다.
// 미터링 리포트용 상수
private static final String RESOURCE_ID = "linux-container";
private static final int BIND = 1;
private static final int UNBIND = 0;
private static final String MEASURE_1 = "sample_service_usage_param1";
private static final String MEASURE_2 = "sample_service_usage_param2";
private static final String MEASURE_3 = "previous_sample_service_usage_param1";
private static final String MEASURE_4 = "previous_sample_service_usage_param2";
private static final String STANDARD_PLAN_ID = "standard";
private static final int PLAN_STANDARD_QUANTITY = 50000000;
private static final int PLAN_EXTRA_QUANTITY = 1000000000;
private static final String SECURED = "true";
/***************************************************
* @description : 리포트 용 JSON 생성
* @title : buildServiceUsage
* @return : JSONObject
***************************************************/
public JSONObject buildServiceUsage(ServiceInstanceBinding binding, int mode) {
String orgId = (String) binding.getAppOrganizationId();
String spaceId = (String) binding.getAppSpaceId();
String planId = (String) binding.getMeteringPlanId();
String appId = (String) binding.getAppGuid();
LocalDateTime now = LocalDateTime.now();
Timestamp timestamp = Timestamp.valueOf(now);
JSONObject jsonObjectUsage = new JSONObject();
jsonObjectUsage.put("start", timestamp.getTime());
jsonObjectUsage.put("end", timestamp.getTime());
jsonObjectUsage.put("organization_id", orgId);
jsonObjectUsage.put("space_id", spaceId);
jsonObjectUsage.put("consumer_id", "app:" + appId);
jsonObjectUsage.put("resource_id", RESOURCE_ID);
jsonObjectUsage.put("plan_id", planId);
jsonObjectUsage.put("resource_instance_id", appId);
JSONArray measuredUsageArr = new JSONArray();
JSONObject measuredUsage1 = new JSONObject();
JSONObject measuredUsage2 = new JSONObject();
JSONObject measuredUsage3 = new JSONObject();
JSONObject measuredUsage4 = new JSONObject();
int quantity = 0;
if (STANDARD_PLAN_ID.equals(planId)) {
quantity = PLAN_STANDARD_QUANTITY;
} else {
quantity = PLAN_EXTRA_QUANTITY;
}
if (mode == BIND) {
measuredUsage1.put("measure", MEASURE_1);
measuredUsage1.put("quantity", quantity);
measuredUsageArr.put(measuredUsage1);
measuredUsage2.put("measure", MEASURE_2);
measuredUsage2.put("quantity", 1);
measuredUsageArr.put(measuredUsage2);
measuredUsage3.put("measure", MEASURE_3);
measuredUsage3.put("quantity", 0);
measuredUsageArr.put(measuredUsage3);
measuredUsage4.put("measure", MEASURE_4);
measuredUsage4.put("quantity", 0);
measuredUsageArr.put(measuredUsage4);
} else { // UNBIND
measuredUsage1.put("measure", MEASURE_1);
measuredUsage1.put("quantity", 0);
measuredUsageArr.put(measuredUsage1);
measuredUsage2.put("measure", MEASURE_2);
measuredUsage2.put("quantity", 0);
measuredUsageArr.put(measuredUsage2);
measuredUsage3.put("measure", MEASURE_3);
measuredUsage3.put("quantity", quantity);
measuredUsageArr.put(measuredUsage3);
measuredUsage4.put("measure", MEASURE_4);
measuredUsage4.put("quantity", 1);
measuredUsageArr.put(measuredUsage4);
}
jsonObjectUsage.put("measured_usage", measuredUsageArr);
return jsonObjectUsage;
}
애플리케이션에서 사용할 서비스를 파스-타 플랫폼을 통하여 생성한다. mongo-db 서비스 팩이 배포하고자 파스-타 플랫폼 환경에 release 되어 있어야 한다. 애플리케이션과 바인딩 과정을 통해 접속정보를 얻을 수 있다.
서비스 생성 (cf marketplace 명령을 통해 서비스 목록과 각 서비스의 플랜을 조회할 수 있다.)
## 서비스 브로커 CF 배포
$ cd openpaas-service-java-broker-mongo
$ cf push
## 서비스 브로커 생성
$ cf create-service-broker <서비스 브로커 명> <인증ID> <인증Password> <서비스 브로커 주소>
예)
$ cf create-service-broker openpaas-mongo-broker admin cloudfoundry http://openpaas-mongo-broker.bosh-lite.com
## 서비스 브로커 확인
$ cf service-brokers
Getting service brokers as admin...
name url
openpaas-mongo-broker http://openpaas-mongo-broker.<파스-타 도메인>
## 서비스 카탈로그 확인
$ cf service-access
Getting service access as admin...
broker: sample-mongodb-broker
service plan access orgs
Mongo-DB default-plan none
## 등록한 서비스 접근 허용
$ cf enable-service-access <서비스명> -p <플랜 명>
예)
$ cf enable-service-access Mongo-DB
# 서비스 생성
$ cf create-service Mongo-DB default-plan mongod_service
2.6.3. API 서비스 연동 샘플 애플리케이션 배포 및 서비스 연결
애플리케이션과 서비스를 연결하는 과정을 '바인드(bind)라고 하며, 이 과정을 통해 서비스에 접근할 수 있는 접속정보를 생성한다.
애플리케이션과 서비스 연결
이때 -c 옵션으로 미터링에 필요한 애플리케이션 환경정보를 세팅한다.
## API 서비스 연동 샘플 애플리케이션 배포
$ cd /binding-test-app
$ cf push
## 서비스 바인드
$ cf bind-service <APP_NAME> <SERVICE_INSTANCE> -c <PARAMETERS_AS_JSON>
예)
$ cf bind-service binding-test-app mongod_service -c '{"app_organization_id":"test05","app_space_id":"testspaceId","metering_plan_id":"standard"}'
## 서비스 연결 확인
$ cf services
Getting services in org real / space ops as admin...
OK
name service plan bound apps last operation
binding-test-app mongod_service standard binding-test-app create succeeded
## 애플리케이션 실행
$ cf start <APP_NAME>
예)
$ cf start binding-test-app
## 형상 확인
$ cf a
Getting apps in org real / space ops as admin...
OK
name requested state instances memory disk urls
binding-test-app started 1/1 512M 512M binding-test-app.<파스-타 도메인>
openpaas-mongo-broker started 1/1 512M 1G openpaas-mongo-broker.<파스-타 도메인>
2.7. 서비스 바인딩 CF-Abacus 연동 테스트
binding-test-app 과 mongo-db 서비스를 바인딩 실행해, CF-Abacus 연동 테스트를 진행 할 수 있다.
CF-Abacus 연동 확인
## 테스트 바인딩
$ cf bind-service binding-test-app mongod_service -c '{"app_organization_id":"testOrgGuid","app_space_id":"testSpaceGuId","metering_plan_id":"standard"}'
<<후략>>
## API 사용량 확인
$ curl 'http://abacus-usage-reporting.<파스-타 도메인>/v1/metering/organizations/<샘플 애플리케이션을 배포한 조직>/aggregated/usage'
예)
$ curl 'http://abacus-usage-reporting.bosh-lite.com/v1/metering/organizations/testOrgGuid /aggregated/usage'
2.8. 단위 테스트
Junit 테스트로 구현 되어 있으며, 테스트 service class 에 대한 부분적 mock 적용을 위하여, owermock-mockito-release-full:1.6.1 을 사용하였다.