AnyCall API Extension Guide - cloud-barista/cb-spider GitHub Wiki

[AnyCall API Extension Overview]

  • 멀티클라우드 공통 제어를 제공하는 CB-Spider API는 특정 Cloud의 세밀한 제어가 불충분할 경우가 있다.
  • AnyCall API 확장(AnyCall API Extension) 기능은 이를 보완하기 위하여
    • 특정 CSP에 특화된 API를 쉽게 추가할 수 있는 표준화된 방법을 제공한다.
  • AnyCall 기능은 아래 그림과 같이
    • (1)AnyCall MSG, (2)AnyCall API, (3)AnyCallHandler 및 추가되는 (4)Ext-Function들로 구성된다.
  • CB-Spider는 API 확장 기능 제공을 위하여
    • 범용으로 호출 가능한 (2)AncyCall API(3)AnyCallHandler를 기본으로 제공하며,
  • 개발자급 사용자는 추가하고자 하는 API(함수)의
    • (1)AnyCall MSG 정의와 (4)Ext-Function의 추가 개발로 API 확장이 가능하다.
  • 각 컴포넌트별 세부 내용은 다음과 같다.
    • (1) AnyCall MSG
      • 추가하고자 하는 API(함수)의 함수 이름, 인자 및 반환 값 등을 정의하는 메시지이며,
      • (2)AnyCall API로 전달하는 Input MSG와 실행 결과로 반환 받는 Output MSG로 구분된다.
      • AnyCall MSG가 포함하는 정보는 다음과 같다.
          - To. Cloud: 함수 실행 대상 클라우드(등록된 Cloud Connection Name)
          - Function ID: 추가할 함수 이름(문자열)
          - input List: 함수 입력 인자 리스트(Key-Value List)
          - output List: 함수 반환 정보 리스트(Key-Value List)
        
    • (2) AnyCall API
      • 사용자가 정의한 (1)AnyCall MSG를 Spider Server에 전달 및 결과를 반환해주는 범용 REST API이며,
      • REST API 세부 규격은 아래 예시를 참고한다.
    • (3) AnyCall Handler
      • AnyCall Handler는 API 확장 대상 Cloud Driver별로 존재하며,
      • (2)AnyCall API를 통해서 전달되는 실행 요청(AnyCall Input MSG) 정보를 활용하여
      • 사용자가 추가한 대상 함수의 호출 및 결과 반환을 관장한다.
    • (4) Ext-Functions
      • 사용자가 추가하고자 하는 API를 구현한 함수로 개발 방법 등 세부 내용은 아래 예시를 참고한다.

[AnyCall API Extension Example]

  • 본 예시는 Mock Driver를 기준으로 가이드 한다.

  • 정규 Mock Driver는 VPC 및 Security Group(SG) 등의 자원 개수 만을 제공하는 API는 제공하지 않는다.

  • 본 예시에서는 AnyCall 기능을 활용하여 VPC, SG에 대한 개수를 제공하는 API 확장 방법에 대해 기술한다.

  • (1) AnyCall MSG 정의 예시는 다음과 같다.

    • To. Cloud(Connection Name): mock-config01(상황에 맞게 가변)
    • Funcion ID: countAll
    • Input List: { "Key" : "rsType", "Value" : "vpc" } // Value= vpc or sg
    • Output List: { "Key" : "Count", "Value" : "10" } // Value= depend on resource number
  • (2) AnyCall REST API 호출 예시는 다음과 같다.

    curl -sX POST http://localhost:1024/spider/anycall -H 'Content-Type: application/json' -d \
    '{
          "ConnectionName" : "mock-config01",
          "ReqInfo" : {
                  "FID" : "countAll",
                  "IKeyValueList" : [{"Key":"rsType", "Value":"vpc"}]
          }
    }' | json_pp
    
    • 실행 결과인 AnyCall Output MSG 예시는 다음과 같다.
    {
       "FID" : "countAll",
       "IKeyValueList" : [
        {
           "Key" : "rsType",
           "Value" : "vpc"
        }
       ],
       "OKeyValueList" : [
        {
           "Key" : "Count",
           "Value" : "10"
        }
       ]
    }
    
  • (3) AnyCallHandler 예시는 다음과 같다.

    • 44-45 Line 참고
      39 func (anyCallHandler *MockAnyCallHandler) AnyCall(callInfo irs.AnyCallInfo) (irs.AnyCallInfo, error) {
      40         cblogger := cblog.GetLogger("CB-SPIDER")
      41         cblogger.Info("Mock Driver: called AnyCall()!")
      42
      43         switch callInfo.FID {
      44         case "countAll" :
      45                 return countAll(anyCallHandler, callInfo)
      46
      47         // add more ...
      48
      49         default :
      50                 return irs.AnyCallInfo{}, errors.New("Mock Driver: " + callInfo.FID + " Function is not implemented!")
      51         }
      52 }
    
  • (4) Ext-Function countAll()의 구현 예시는 다음과 같다.

     55 ///////////////////////////////////////////////////////////////////
     56 // implemented by developer user, like 'countAll(rsType string) int'
     57 ///////////////////////////////////////////////////////////////////
     58 func countAll(anyCallHandler *MockAnyCallHandler, callInfo irs.AnyCallInfo) (irs.AnyCallInfo, error) {
     59         cblogger := cblog.GetLogger("CB-SPIDER")
     60         cblogger.Info("Mock Driver: called AnyCall()/countAll()!")
     61
     62         mockName := anyCallHandler.MockName
     63
     64         // Input Arg Validation
     65         if callInfo.IKeyValueList == nil {
     66                 return irs.AnyCallInfo{}, errors.New("Mock Driver: " + callInfo.FID + "'s Argument is empty!")
     67         }
     68         if callInfo.IKeyValueList[0].Key != "rsType" {
     69                 return irs.AnyCallInfo{}, errors.New("Mock Driver: " + callInfo.FID + "'s Argument is not 'rsType'!")
     70         }
     71
     72         // get info
     73         strCount := ""
     74         switch callInfo.IKeyValueList[0].Value {
     75         case "vpc":
     76                 infoList, ok := vpcInfoMap[mockName]
     77                 if !ok {
     78                         strCount = "0"
     79                 } else {
     80                         strCount = strconv.Itoa(len(infoList))
     81                 }
     82         case "sg":
     83                 infoList, ok := securityInfoMap[mockName]
     84                 if !ok {
     85                         strCount = "0"
     86                 } else {
     87                         strCount = strconv.Itoa(len(infoList))
     88                 }
     89         }
     90
     91         // make results
     92         if callInfo.OKeyValueList == nil {
     93                 callInfo.OKeyValueList = []irs.KeyValue{}
     94         }
     95         callInfo.OKeyValueList = append(callInfo.OKeyValueList, irs.KeyValue{"Count", strCount} )
     96
     97         return callInfo, nil
     98 }
    

  • 만일, 대상 Driver에 AnyCallHandler가 존재하지 않는다면 다음을 참고하여 추가한다.
  • 신규 AnyCallHandler 추가하는 방법
    • (1) 다음 예시를 참고하여 {driver}/connect/* 위치에 CreateAnyCallHandler() 함수 추가
    • (2) 다음 예시를 참고하여 {driver}/resources/AnyCallHandler.go를 추가