IBM Cloud Docs
App Configuration 服务器 SDK for Go

App Configuration 服务器 SDK for Go

App Configuration 服务提供 SDK 以与 Golang Web 和移动应用程序,微服务以及分布式环境集成。

先决条件

以下是使用 App Configuration 服务 SDK for Go 的先决条件:

  • Go V 1.16 或更高版本

集成服务器 SDK for Go

已收回 App Configuration Go SDK 的 v1.x.x 版本。

App Configuration 服务提供 SDK 以与 Golang Web 和移动应用程序,微服务以及分布式环境集成。 您可以通过集成 App Configuration SDK 来评估属性和功能标志的值。

  1. 使用 git 存储库中的以下代码来安装 SDK。

    go get -u github.com/IBM/appconfiguration-go-sdk@latest
    
  2. 在 Golang 微服务或应用程序中,包含 SDK 模块,包括:

    import (
       AppConfiguration "github.com/IBM/appconfiguration-go-sdk/lib"
    )
    

    运行 go mod tidy 以下载并安装新的依赖关系,并更新 Go 应用程序的 go.mod 文件。

  3. 初始化 SDK 以与 App Configuration 服务实例连接。

    collectionId := "airlines-webapp"
    environmentId := "dev"
    
    appConfigClient := AppConfiguration.GetInstance()
    appConfigClient.Init("region", "guid", "apikey")
    appConfigClient.SetContext(collectionId, environmentId)
    

    其中,

    • region:创建 App Configuration 服务实例的区域名称。 点击此处 查看支持的地点列表。 例如:- us-south, au-syd 等。
    • guid: App Configuration 服务的实例标识。 从 App Configuration 服务仪表板的服务凭证部分获取此信息。
    • apiKey: App Configuration 服务的 ApiKey。 从 App Configuration 服务仪表板的服务凭证部分获取此信息。
    • collectionId: 在 App Configuration 服务实例中创建的集合的标识。
    • environmentId: 在“环境”部分下的 App Configuration 服务实例中创建的环境的标识。

    init()setContext() 是初始化方法,需要 仅一次 使用 appConfigClient 启动。 初始化后,可以使用 AppConfiguration.GetInstance() 跨模块获取 appConfigClient

使用专用端点

通过使用仅可通过 IBM Cloud 专用网络访问的专用端点,设置 SDK 以连接到 App Configuration 服务。

appConfigClient.UsePrivateEndpoint(true)

必须先完成此操作,然后才能在 SDK 上调用 Init 函数。

用于将持久高速缓存用于配置的选项

要使应用程序和 SDK 继续操作,即使在 App Configuration 服务停机的不太可能的场景中,在应用程序重新启动期间,您也可以将 SDK 配置为使用持久高速缓存来工作。 SDK 使用持久高速缓存来存储在应用程序重新启动期间可用的 App Configuration 数据。

// 1. default (without persistent cache)
appConfiguration.SetContext(collectionId, environmentId)
// 2. with persistent cache
appConfiguration.SetContext(collectionId, environmentId, AppConfiguration.ContextOptions{
   PersistentCacheDirectory: "/var/lib/docker/volumes/",
})

其中 persistentCacheDirectory: 具有用户读写许可权的目录的绝对路径。 SDK 在指定目录中创建文件 AppConfiguration.json,并将其用作持久高速缓存以存储 App Configuration 服务信息。

启用持久高速缓存时,SDK 会在持久高速缓存中保留最后已知的良好配置。 如果无法访问 App Configuration 服务器,那么会将持久高速缓存中的最新配置装入到应用程序以继续工作。

确保在任何情况下都不会丢失或删除高速缓存文件。 例如,请考虑重新启动 Kubernetes pod 并且高速缓存文件 (appconfiguration.json) 存储在 pod 的临时卷中的情况。 当 pod 重新启动时,kubernetes 会破坏 pod 中的 ephermal 卷,从而删除高速缓存文件。 因此,通过提供持久目录的正确绝对路径,确保 SDK 创建的高速缓存文件始终存储在持久卷中。

脱机选项

SDK 还设计为提供配置,并在不连接到 App Configuration 服务的情况下执行功能标志和属性评估。

appConfiguration.SetContext(collectionId, environmentId, AppConfiguration.ContextOptions{
   BootstrapFile: "saflights/flights.json",
   LiveConfigUpdateEnabled: false,
})

其中,

  • BootstrapFile: JSON 文件的绝对路径,其中包含配置详细信息。 请确保提供正确的 JSON 文件。 您可以使用 IBM Cloud App Configuration CLI 的 ibmcloud ac export 命令来生成此文件。

  • LiveConfigUpdateEnabled: 从服务器进行实时配置更新。 如果不能从服务器访存新配置值,请将此值设置为 false。 缺省情况下,此值处于启用状态。

使用与属性和功能相关的 API 的示例

请参阅列出的使用属性和功能相关 API 的示例。

获取单一功能

feature, err := appConfigClient.GetFeature("online-check-in")
if err == nil {
   fmt.Println("Feature Name", feature.GetFeatureName())
   fmt.Println("Feature Id", feature.GetFeatureID())
   fmt.Println("Feature Type", feature.GetFeatureDataType())

   if (feature.IsEnabled()) {
      // feature flag is enabled
   } else {
      // feature flag is disabled
   }
}

获取所有功能

features, err := appConfigClient.GetFeatures()
if err == nil {
   feature := features["online-check-in"]

   fmt.Println("Feature Name", feature.GetFeatureName())
   fmt.Println("Feature Id", feature.GetFeatureID())
   fmt.Println("Feature Type", feature.GetFeatureDataType())
   fmt.Println("Is feature enabled?", feature.IsEnabled())
}

功能评估

您可以使用 feature.GetCurrentValue(entityId, entityAttributes) 方法来评估功能标志的值。GetCurrentValue 根据评估返回“已启用”,“已禁用”或“已覆盖”值之一。

entityId := "john_doe"
entityAttributes := make(map[string]interface{})
entityAttributes["city"] = "Bangalore"
entityAttributes["country"] = "India"

featureVal := feature.GetCurrentValue(entityId, entityAttributes)
  • entityId: entityId 是与将对功能部件进行求值的实体相关的字符串标识。 例如,实体可能是在移动设备上运行的应用程序实例,在云上运行的微服务或运行该微服务的基础结构组件。 对于要与 App Configuration进行交互的任何实体,它必须提供唯一的实体标识。

  • entityAttributes: entityAttributes 是类型为 map[string]interface{} 的映射,由属性名称及其定义指定实体的值组成。 如果未使用任何目标定义配置功能标志,那么这是可选参数。 如果配置了目标,那么必须为规则评估提供 entityAttributes。 属性是用于定义段的参数。 SDK 使用属性值来确定指定的实体是否满足目标规则,并返回相应的功能标志值。

获取单个属性

property, err := appConfigClient.GetProperty("check-in-charges")
if err == nil {
   fmt.Println("Property Name", property.GetPropertyName())
   fmt.Println("Property Id", property.GetPropertyID())
   fmt.Println("Property Type", property.GetPropertyDataType())
}

获取所有属性

properties, err := appConfigClient.GetProperties()
if err == nil {
   property := properties["check-in-charges"]

   fmt.Println("Property Name", property.GetPropertyName())
   fmt.Println("Property Id", property.GetPropertyID())
   fmt.Println("Property Type", property.GetPropertyDataType())
}

属性评估

您可以使用 property.GetCurrentValue(entityId, entityAttributes) 方法来评估属性的值。GetCurrentValue 根据求值返回缺省属性值或其覆盖值。

entityId := "john_doe"
entityAttributes := make(map[string]interface{})
entityAttributes["city"] = "Bangalore"
entityAttributes["country"] = "India"

propertyVal := property.GetCurrentValue(entityId, entityAttributes)
  • entityId: entityId 是与将针对其对属性进行求值的实体相关的字符串标识。 例如,实体可能是在移动设备上运行的应用程序实例,在云上运行的微服务或运行该微服务的基础结构组件。 对于要与 App Configuration进行交互的任何实体,它必须提供唯一的实体标识。

  • entityAttributes: entityAttributes 是类型为 map[string]interface{} 的映射,由属性名称及其定义指定实体的值组成。 如果属性未配置任何目标定义,那么这是可选参数。 如果配置了目标,那么必须为规则评估提供 entityAttributes。 属性是用于定义段的参数。 SDK 使用属性值来确定指定的实体是否满足目标规则,并返回相应的属性值。

获取私钥属性

secretPropertyObject, err := appConfiguration.GetSecret(propertyID, secretsManagerObject)
  • propertyID: propertyID 是唯一字符串标识,使用此标识,您将能够访存提供了访存私钥所必需的数据的属性。

  • secretsManagerObject: secretsManagerObject 是 Secrets Manager 变量或对象,将用于在私钥属性求值期间获取私钥。 有关如何创建 Secrets Manager 对象的更多信息,请参阅 此处

评估私钥属性

使用 secretPropertyObject.GetCurrentValue(entityId, entityAttributes) 方法来评估私钥属性的值。GetCurrentValue 返回基于求值的私钥值。

entityId := "john_doe"
entityAttributes := make(map[string]interface{})
entityAttributes["city"] = "Bangalore"
entityAttributes["country"] = "India"

getSecretRes, detailedResponse, err := secretPropertyObject.GetCurrentValue(entityId, entityAttributes)
  • entityId: entityId 是与将针对其对属性进行求值的实体相关的字符串标识。 例如,实体可能是在移动设备上运行的应用程序实例,在云上运行的微服务或运行该微服务的基础结构组件。 对于要与 App Configuration进行交互的任何实体,它必须提供唯一的实体标识。

  • entityAttributes: entityAttributes 是类型为 map[string]interface{} 的映射,由属性名称及其定义指定实体的值组成。 如果属性未配置任何目标定义,那么这是可选参数。 如果配置了目标,那么必须为规则评估提供 entityAttributes。 属性是用于定义段的参数。 SDK 使用属性值来确定指定的实体是否满足目标规则,并返回相应的属性值。

如何从响应访问有效内容私钥数据

//make sure this import statement is added
import (sm "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1")

secret := getSecretRes.Resources[0].(*sm.SecretResource)
secretData := secret.SecretData.(map[string]interface{})
payload := secretData["payload"]

GetCurrentValue 将作为响应的一部分发送三个对象。

  • getSecretRes: 这将提供元数据和有效内容。
  • detailedResponse: 这将提供包含 HTTP 响应头数据,元数据和有效内容的完整数据。
  • err: 如果请求无效或由于某种原因失败,那么这将给出错误响应。

secretData["payload"] 将返回 interface{},以便根据您执行类型强制类型转换所需的数据。

跨其他模块访存 appConfigClient

一旦SDK初始化,appConfigClient 就可以通过其他模块获取,如下所示:

// **other modules**

import (
   AppConfiguration "github.com/IBM/appconfiguration-go-sdk/lib"
)

appConfigClient := AppConfiguration.GetInstance()
feature, err := appConfigClient.GetFeature("online-check-in")
if (err == nil) {
   enabled := feature.IsEnabled()
   featureValue := feature.GetCurrentValue(entityId, entityAttributes)
}

支持的数据类型

您可以使用 App Configuration配置功能部件标志和属性,支持以下数据类型 :Boolean,Numeric,String 和 SecretRef。 字符串数据类型可以是文本字符串,JSON 或 YAML。 SDK 将处理表中显示的每种格式。

输出示例
功能部件或属性值 数据类型 数据格式 GetCurrentValue() 返回的数据类型 示例输出
true BOOLEAN 不适用 bool true
25 NUMERIC 不适用 float64 25
{
"secret_type": "kv",
"id": "secret_id_data_here",
"sm_instance_crn": "crn_data_added-here"
}
SECRETREF (this type is applicable only for Property) not applicable map[string]interface{} {
"metadata": {
"collection_type":"application/vnd.ibm.secrets-manager.secret+json",
"collection_total": 1
}, "resources": [{"created_by": "iam-ServiceId-e4a2f0a4-3c76-4bef-b1f2-fbeae11c0f21",
"creation_date": "2020-10-05T21:33:11Z",
"crn": "crn:v1:bluemix:public:secrets-manager:us-south:a/a5ebf2570dcaedf18d7ed78e216c263a:f1bc94a6-64aa-4c55-b00f-f6cd70e4b2ce:secret:cb7a2502-8ede-47d6-b5b6-1b7af6b6f563",
"description": "Extended description for this secret.",
"expiration_date": "2021-01-01T00:00:00Z",
"id": "cb7a2502-8ede-47d6-b5b6-1b7af6b6f563",
"labels": ["dev","us-south"],
"last_update_date": "2020-10-05T21:33:11Z",
"name": "example-arbitrary-secret",
"secret_data": {"payload": "secret-data"},
"secret_type": "arbitrary",
"state": 1,
"state_description": "Active",
"versions_total": 1,
"versions": [{"created_by": "iam-ServiceId-222b47ab-b08e-4619-b68f-8014a2c3acb8","creation_date": "2020-11-23T20:15:01Z","id": "50277266-d706-4b3e-badb-f07257f8f581","payload_available": true,"downloaded": true}],"locks_total": 2}]
}
Note: Along with the above data you will also provide the detailedResponse and error data.
"a string text" STRING TEXT string a string text
{"firefox": {
"name": "Firefox",
"pref_url": "about:config"
}}
字符串 JSON map[string]interface{} map[browsers:map[firefox:map[name:Firefox pref_url:about:config]]]
men:
- John Smith
- Bill Jones
women:
- Mary Smith
- Susan Williams
STRING YAML map[string]interface{} map[men:[John Smith Bill Jones] women:[Mary Smith Susan Williams]]

功能标志

feature, err := appConfigClient.GetFeature("json-feature")
if err == nil {
   feature.GetFeatureDataType() // STRING
   feature.GetFeatureDataFormat() // JSON

   // Example (traversing the returned map)
   result := feature.GetCurrentValue(entityID, entityAttributes) // JSON value is returned as a Map
   result.(map[string]interface{})["key"] // returns the value of the key
}

feature, err := appConfigClient.GetFeature("yaml-feature")
if err == nil {
   feature.GetFeatureDataType() // STRING
   feature.GetFeatureDataFormat() // YAML

   // Example (traversing the returned map)
   result := feature.GetCurrentValue(entityID, entityAttributes) // YAML value is returned as a Map
   result.(map[string]interface{})["key"] // returns the value of the key
}

属性

property, err := appConfigClient.GetProperty("json-property")
if err == nil {
   property.GetPropertyDataType() // STRING
   property.GetPropertyDataFormat() // JSON

   // Example (traversing the returned map)
   result := property.GetCurrentValue(entityID, entityAttributes) // JSON value is returned as a Map
   result.(map[string]interface{})["key"] // returns the value of the key
}

property, err := appConfigClient.GetProperty("yaml-property")
if err == nil {
   property.GetPropertyDataType() // STRING
   property.GetPropertyDataFormat() // YAML

   // Example (traversing the returned map)
   result := property.GetCurrentValue(entityID, entityAttributes) // YAML value is returned as a Map
   result.(map[string]interface{})["key"] // returns the value of the key
}

侦听属性和功能部件更改

要侦听数据更改,请在应用程序中添加以下代码:

appConfigClient.RegisterConfigurationUpdateListener(func () {
   // **add your code**
   // To find the effect of any configuration changes, you can call the feature or property related methods

   // feature, err := appConfigClient.GetFeature("json-feature")
   // newValue := feature.GetCurrentValue(entityID, entityAttributes)
})

访存最新数据

appConfigClient.FetchConfigurations()