네이버 클라우드의 insight(구 monitoring)에 있는 metric서비스를 spaceone의 멀티클라우드 플랫폼인 cloudforet에 추가하는 코드를 작성한다.
네이버 클라우드 서비스를 spaceone에 가져오는 형태는 connetor->manager->spaceone에 plugin 하는 단계로 구성되어 있다.
오늘은 네이버 클라우드의 api를 사용해서 metric 서비스 중 metric list와 list의 data를 connect 작업을 한다.
경로는 3가지가 있다.
src/spaceone/monitoring/connector/naver_cloud_connector/init.py
src/spaceone/monitoring/connector/naver_cloud_connector/metric.py
test/connector/test_naver_cloud_connector.py
test에서는 테스트를 하고,
init에서는 네이버 클라우드 api를 이용해서 연결하고,
metric에서는 가져오려는 데이터의 구조에 맞게 변형한다.
코드를 보는 순서는 test->init->metric->test 이다.
test_connector.py
AKI = os.environ.get('NCLOUD_ACCESS_KEY_ID', None)
SK = os.environ.get('NCLOUD_SECRET_KEY', None)
class TestNaverCloudConnector(unittest.TestCase):
secret_data = {
'ncloud_access_key_id': AKI,
'ncloud_secret_key': SK,
}
@classmethod
def setUpClass(cls):
config.init_conf(package='spaceone.inventory')
cls.schema = 'naver_client_secret'
super().setUpClass()
@classmethod
def tearDownClass(cls) -> None:
super().tearDownClass()
def test_list_metrics(self):
options = {
"prodKey": "460438727509020672"
}
secret_data = self.secret_data
endpoint = '/cw_fea/real/cw/api/rule/group/metric/search'
self.metric_connector = NaverCloudConnector(secret_data=secret_data, options=options) #init으로 가서 connect를 하게 된다.
self.metric_connector.set_connnect({}, options, secret_data, endpoint)
metrics_info = self.metric_connector.list_metrics(options) #options를 통해 prod_key를 전달한다. 받을 땐 딕셔너리 형태인 **kwargs로 받는다.
def test_get_metric_data(self):
# end = datetime.utcnow()
# start = end - timedelta(minutes=60*60*7*30)
# 위와 같은 방식으로 나중에 시간 변경 다 해줘야 한다.
options = {
"cw_key": "460438727509020672",
"metric": "concurrent_session",
"dimensions": {
"loadBalancerPort": "80",
"layerType": "APPLICATION",
"loadBalancerName": "ing-spaceone-ncloudspace-1423c",
"networkType": "PUBLIC"
},
"timeStart": '1712759400000',
"timeEnd": '1712762999000'
}
secret_data = self.secret_data
endpoint = '/cw_fea/real/cw/api/data/query'
self.metric_connector = NaverCloudConnector(secret_data=secret_data, options=options) #init으로 가서 connect를 하게 된다. metric_connector라는 객체 형성.
self.metric_connector.set_connnect({}, options, secret_data, endpoint)
metrics_info = self.metric_connector.get_metric_data(
options.get('cw_key'),
options.get('metric'),
options.get('dimensions'),
options.get('timeStart'),
options.get('timeEnd'),
) #이 5개 값이 순서대로 init의 *args에 튜플형태로 들어간다.
print("metrics_info: ", metrics_info)
if __name__ == "__main__":
unittest.main(testRunner=RichTestRunner)
__init__.py
class NaverCloudConnector(BaseConnector):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.metric_client = None
self.base_url = 'https://cw.apigw.ntruss.com'
def make_signature(self, access_key, secret_key, method, uri, timestamp):
message = method + " " + uri + "\n" + timestamp + "\n" + access_key
message = bytes(message, 'UTF-8')
secret_key = bytes(secret_key, 'UTF-8')
signingKey = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())
return signingKey.decode()
def set_connnect(self, options: dict, secret_data: dict, endpoint):
self.url = f"{self.base_url}{endpoint}"
self.endpoint = endpoint
method = 'POST'
timestamp = str(int(time.time() * 1000))
metric_access_key = secret_data['ncloud_access_key_id']
metric_secret_key = secret_data['ncloud_secret_key']
headers = {
'x-ncp-apigw-signature-v2': self.make_signature(metric_access_key, metric_secret_key, method,
endpoint,
timestamp),
'x-ncp-apigw-timestamp': timestamp,
'x-ncp-iam-access-key': metric_access_key,
'Content-Type': 'application/json'
}
if options is None:
options = {}
self.metric_client = requests.post(self.url, headers=headers, json=options).json()
#list_metric의 경우, client는 {'metrics': [{'dataType': 'FLOAT', 'desc': 'Concurrent Connection', 'dimensions': [{'dim': 'layerType', 'val': 'APPLICATION'}, {'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ing-spaceone-ncloudspace-1423c'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'concurrent_session', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Concurrent Connection', 'dimensions': [{'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'loadBalancerPort', 'val': '443'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'concurrent_session', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Concurrent Connection', 'dimensions': [{'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'concurrent_session', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Connection per Second', 'dimensions': [{'dim': 'layerType', 'val': 'APPLICATION'}, {'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ing-spaceone-ncloudspace-1423c'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'connections_per_second', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Connection per Second', 'dimensions': [{'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'loadBalancerPort', 'val': '443'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'connections_per_second', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Connection per Second', 'dimensions': [{'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'connections_per_second', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'dimensions': [{'dim': 'layerType', 'val': 'APPLICATION'}, {'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ing-spaceone-ncloudspace-1423c'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_in_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'dimensions': [{'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'loadBalancerPort', 'val': '443'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_in_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'dimensions': [{'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_in_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Traffic Out', 'dimensions': [{'dim': 'layerType', 'val': 'APPLICATION'}, {'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ing-spaceone-ncloudspace-1423c'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_out_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Traffic Out', 'dimensions': [{'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'loadBalancerPort', 'val': '443'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_out_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}, {'dataType': 'FLOAT', 'desc': 'Traffic Out', 'dimensions': [{'dim': 'loadBalancerPort', 'val': '80'}, {'dim': 'loadBalancerName', 'val': 'ingress-ngi-ingress-ngin-7e287'}, {'dim': 'layerType', 'val': 'NETWORK_PROXY'}, {'dim': 'networkType', 'val': 'PUBLIC'}], 'idDimension': 'instanceId', 'metric': 'traffic_out_byte', 'options': {'Min1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min5': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Min30': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Hour2': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG'], 'Day1': ['COUNT', 'SUM', 'MAX', 'MIN', 'AVG']}, 'prodKey': '460438727509020672'}], 'prodKey': '460438727509020672'}
#get_metric_data의 경우, client는 [[1712759400000, 0.0], [1712759460000, 1.0], [1712759520000, 0.0], [1712759580000, 0.0], [1712759640000, 0.0], [1712759700000, 0.0], [1712759760000, 0.0], [1712759820000, 0.0], [1712759880000, 0.0], [1712759940000, 0.0], [1712760000000, 0.0], [1712760060000, 0.0], [1712760120000, 1.0], [1712760180000, 1.0], [1712760240000, 0.0], [1712760300000, 0.0], [1712760360000, 1.0], [1712760420000, 0.0], [1712760480000, 0.0], [1712760540000, 0.0], [1712760600000, 0.0], [1712760660000, 0.0], [1712760720000, 0.0], [1712760780000, 0.0], [1712760840000, 0.0], [1712760900000, 2.0], [1712760960000, 0.0], [1712761020000, 0.0], [1712761080000, 0.0], [1712761140000, 0.0], [1712761200000, 1.0], [1712761260000, 0.0], [1712761320000, 0.0], [1712761380000, 0.0], [1712761440000, 0.0], [1712761500000, 0.0], [1712761560000, 0.0], [1712761620000, 0.0], [1712761680000, 0.0], [1712761740000, 0.0], [1712761800000, 0.0], [1712761860000, 0.0], [1712761920000, 0.0], [1712761980000, 0.0], [1712762040000, 0.0], [1712762100000, 0.0], [1712762160000, 0.0], [1712762220000, 0.0], [1712762280000, 0.0], [1712762340000, 0.0], [1712762400000, 0.0], [1712762460000, 0.0], [1712762520000, 0.0], [1712762580000, 0.0], [1712762640000, 0.0], [1712762700000, 0.0], [1712762760000, 0.0], [1712762820000, 0.0], [1712762880000, 0.0], [1712762940000, 0.0]]
def list_metrics(self, **kwargs): #prodkey 딕셔너리 형태
return NaverCloudMetric(self.metric_client, self.url).list_metrics(**kwargs)
def get_metric_data(self, *args): #options보면 튜플 형태
return NaverCloudMetric(self.metric_client, self.url).get_metric_data(*args)
metric.py
class NaverCloudMetric(object):
def __init__(self, client, url):
self.client = client
self.url = url
def list_metrics(self):
metric_lists = []
metric_info_lists = self.client['metrics']
for metric_info in metric_info_lists:
metric_lists.append(metric_info.get('metric'))
return metric_lists
def get_metric_data(self, cw_key, metric, dimensions, timeStart, timeEnd):
metrics_data = self.client
metric_data = []
for data in metrics_data:
metric_data.append(data[1])
return metric_data
안녕하세요, 네이버 클라우드 플랫폼입니다.
네이버클라우드의 기술 콘텐츠 리워드 프로그램 ‘이달의 Nclouder(4월)’ 도전자로 초대합니다 🙂
네이버 클라우드 플랫폼 서비스와 관련된 모든 주제로 5/2(목) 23시까지 신청 가능합니다. (*4월 작성 콘텐츠 한정 신청 가능)
Ncloud 크레딧을 포함한 다양한 리워드가 준비되어 있으니 많은 관심 부탁드립니다!
자세한 내용은 아래 링크에서 확인부탁드립니다.
https://blog.naver.com/n_cloudplatform/223410617146
신청 링크
https://navercloud.typeform.com/to/lF8NUaCF