V2 Migration Guide
EdgeX 2.0
For the EdgeX 2.0 (Ireland) release there are many backward breaking changes. These changes require custom Application Services and custom profiles (app-service-configurable) to be migrated. This section outlines the necessary steps for this migration.
Custom Application Services
Configuration
The migration of any Application Service's configuration starts with migrating configuration common to all EdgeX services. See the V2 Migration of Common Configuration section for details. The remainder of this section focuses on configuration specific to Application Services.
SecretStoreExclusive
The SecretStoreExclusive section has been removed in EdgeX 2.0. With EdgeX 2.0 all SecretStores are exclusive, so the existing SecretStore section is all that is required. Services requiring known secrets such as redisdb must inform the Security SecretStore Setup service (via environment variables) that the application service requires the secret added to its SecretStore. See the Configuring Add-on Services section for more details.
Clients
The client used for the version validation check has changed to being from Core Metadata, rather than Core Data. This is because Core Data is now optional when persistence isn't required since all Device Services publish directly to the EdgeX MessageBus. The configuration for Core Metadata is the only Clients entry required, all other (see below) are optional based on use case needs.
Note
The port numbers for all EdgeX services have changed which must be reflected in the Clients configuration. Please see the Default Service Ports section for complete list of the new port assignments.
Example - Core Metadata client configuration
[Clients]
[Clients.core-metadata]
Protocol = "http"
Host = "localhost"
Port = 59881
Example - All available clients configured with new port numbers
[Clients]
# Used for version check on start-up
# Also used for DeviceService, DeviceProfile and Device clients
[Clients.core-metadata]
Protocol = "http"
Host = "localhost"
Port = 59881
# Used for Event client which is used by PushToCoreData function
[Clients.core-data]
Protocol = "http"
Host = "localhost"
Port = 59880
# Used for Command client
[Clients.core-command]
Protocol = "http"
Host = "localhost"
Port = 59882
# Used for Notification and Subscription clients
[Clients.support-notifications]
Protocol = "http"
Host = "localhost"
Port = 59860
Trigger
The Trigger section (previously named Binding) has been restructured with EdgexMessageBus (previously named MessageBus) and ExternalMqtt (previously named MqttBroker ) moved under it. The SubscribeTopics (previously named SubscribeTopic) has been moved under the EdgexMessageBus.SubscribeHost and ExternalMqtt sections. The PublishTopic has been moved under the EdgexMessageBus.PublishHost and ExternalMqtt sections.
EdgeX MessageBus
If your Application Service is using the EdgeX MessageBus trigger, you can then simply copy the complete Trigger configuration from the example below and tweak it as needed.
Example - EdgeX MessageBus trigger configuration
[Trigger]
Type="edgex-messagebus"
[Trigger.EdgexMessageBus]
Type = "redis"
[Trigger.EdgexMessageBus.SubscribeHost]
Host = "localhost"
Port = 6379
Protocol = "redis"
SubscribeTopics="edgex/events/#"
[Trigger.EdgexMessageBus.PublishHost]
Host = "localhost"
Port = 6379
Protocol = "redis"
PublishTopic="example"
[Trigger.EdgexMessageBus.Optional]
AuthMode = "usernamepassword" # required for redis messagebus (secure or insecure).
SecretName = "redisdb"
From the above example you can see the improved structure and the following changes:
- Default
EdgexMessageBustype has changed fromZeroMQtoRedis. - Type value for
Redishas changed fromredistreamstoredis. This is because the implementation no longer uses Redis Streams. It now uses Redis Pub/Sub. SubscribeTopicsis now plural since it now accepts a comma separated list of topics. The default value uses a multi-level topic with a wild card. This is because Core Data and Device Services now publish to a multi-level topics which haveedgex/eventsas their base. This allows Application Services to filter by topic rather then receive the data and then filter it out via a pipeline filter function. See the Filter By Topics section for more details.- The EdgeX MessageBus using Redis is a Secure MessageBus, thus the addition of the
AuthModeandSecretNamesettings which allow the credentials to be pulled from the service's SecretStore. See the Secure MessageBus secure for more details.
External MQTT
If your Application service is using the External MQTT trigger do the following:
- Move your existing
MqttBrokerconfiguration under theTriggersection (renaming it toExternalMqtt) - Move your
SubscribeTopic(renaming it toSubscribeTopics) under theExternalMqttsection. - Move your
PublishTopicunder theExternalMqttsection.
Example - External MQTT trigger configuration
[Trigger]
Type="external-mqtt"
[Trigger.ExternalMqtt]
Url = "tcp://broker.hivemq.com:1883"
SubscribeTopics = "edgex-trigger"
PublishTopic = "edgex-trigger-response"
ClientId = "app-my-service"
ConnectTimeout = "30s"
AutoReconnect = false
KeepAlive = 60
QoS = 0
Retain = false
SkipCertVerify = false
SecretPath = ""
AuthMode = "none"
HTTP
The HTTP trigger configuration has not changed beyond the renaming of Binding to Trigger.
Example - HTTP trigger configuration
[Trigger]
Type="http"
Code
Dependencies
You first need to update the go.mod file to specify go 1.16 and the V2 versions of the App Functions SDK and any EdgeX go-mods directly used by your service. Note the extra /v2 for the modules.
Example go.mod for V2
module <your service>
go 1.16
require (
github.com/edgexfoundry/app-functions-sdk-go/v2 v2.0.0
github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0
)
Once that is complete then the import statements for these dependencies must be updated to include the /v2 in the path.
Example import statements for V2
import (
...
"github.com/edgexfoundry/app-functions-sdk-go/v2/pkg/interfaces"
"github.com/edgexfoundry/go-mod-core-contracts/v2/dtos"
)
New APIs
Next changes you will encounter in your code are that the AppFunctionsSDK and Context structs have been abstracted into the new ApplicationService and AppFunctionContext APIs. See the Application Service API and App Function Context API sections for complete details on these new APIs. The following sections cover migrating your code for these new APIs.
main()
The following changes to your main() function will be necessary.
Create and Initialize
Your main() will change to use a factory function to create and initialize the Application Service instance, rather than create instance of AppFunctionsSDK and call Initialize()
Example - Create Application Service instance
const serviceKey = "app-myservice"
...
service, ok := pkg.NewAppService(serviceKey)
if !ok {
os.Exit(-1)
}
Example - Create Application Service instance with Target Type specified
const serviceKey = "app-myservice"
...
service, ok := pkg.NewAppServiceWithTargetType(serviceKey, &[]byte{})
if !ok {
os.Exit(-1)
}
Since the factory function logs all errors, all you need to do is exit if it returns false.
Logging Client
The Logging client is now accessible from the service.LoggingClient() API.
New extended Logging Client API
The Logging Client API now has formatted versions of all the logging APIs, which are Infof, Debugf, Tracef, Warnfand Errorf. If your code uses fmt.Sprintf to format your log messages then it can now be simplified by using these new APIs.
Application Settings
The access functions for retrieving the service's custom Application Settings (ApplicationSettings, GetAppSettingStrings, and GetAppSetting ) have not changed. An improved capability to have structured custom configuration has been added. See the Structure Custom Configuration section for more details.
Functions Pipeline
Setting the Functions Pipeline has not changed, but the name of some built in functions have changed and new ones have been added. See the Built-In Pipeline Functions section for more details.
Example - Setting Functions Pipeline
if err := service.SetFunctionsPipeline(
transforms.NewFilterFor(deviceNames).FilterByDeviceName,
transforms.NewConversion().TransformToXML,
transforms.NewHTTPSender(exportUrl, "application/xml", false).HTTPPost,
); err != nil {
lc.Errorf("SetFunctionsPipeline returned error: %s", err.Error())
os.Exit(-1)
}
MakeItRun
The MakeItRun API has not changed.
Example - Call to MakeItRun
err = service.MakeItRun()
if err != nil {
lc.Errorf("MakeItRun returned error: %s", err.Error())
os.Exit(-1)
}
Custom Pipeline Functions
Pipeline Function signature
The major change to custom Pipeline Functions for EdgeX 2.0 is the new function signature which drives all the other changes.
Example - New Pipeline Function signature
type AppFunction = func(ctx AppFunctionContext, data interface{}) (bool, interface{})
This function signature passes in an instance of the new AppFunctionContext API for the context and now has only a single data instance for the function to operate on.
Return Values
The definitions for the Pipeline Function return values have not changed.
Data
The data passed in either set to a single instance for the function to process or nil. Now you no longer need to check the length of the incoming data.
Example
if data == nil {
return false, errors.New("No Data Received")
}
Logging Client
The Logging client is now accessible from the ctx.LoggingClient() API.
Clients
The available clients have changed with a few additions and ValueDescriptorClient has been removed. See the Context Clients section for complete list of available clients.
ResponseData
The SetResponseData and ResponseData APIs replace the previous Complete function and direct access to the OutputData field.
ResponseContentType
The SetResponseContentType and ResponseContentType APIs replace the previous direct access to the ResponseContentType field.
RetryData
The SetRetryData API replaces the SetRetryData function and direct access to the RetryData field.
MarkAsPushed
The MarkAsPushed capability has been removed
PushToCore
The PushToCore API replaces the PushToCoreData function. The API signature has changed. See the PushToCore section for more details.
New Capabilities
Some new capabilities have been added to the new AppFunctionContext API. See the App Function Context API section for complete details.
App Service Configurable Profiles
Custom profiles used with App Service Configurable are configuration files. These follow the same migration above for custom Application Service configuration, except for the Configurable Functions Pipeline items. The following are the changes for the Configurable Functions Pipeline:
FilterByValueDescriptorchanged toFilterByResourceName. See the FilterByResourceName section for details.TransformToXMLandTransformToJSONhave been collapsed intoTransformwith additional parameters. See the Transform section for more details.CompressWithGZIPandCompressWithZLIBhave been collapsed intoCompresswith additional parameters. See the Compress section for more details.EncryptWithAEShas been changed toEncryptwith additional parameters. See the Encrypt section for more details.BatchByCount,BatchByTimeandBatchByTimeAndCounthave been collapsed intoBatchwith additional parameters. See the Batch section for more details.SetOutputDatahas been renamed toSetResponseData. See the SetResponseData section for more details.PushToCoreparameters have changed. See the PushToCore section for more details.HTTPPost,HTTPPostJSON,HTTPPostXML,HTTPPut,HTTPPutJSONandHTTPPutXMLhave been collapsed intoHTTPExportwith additional parameters. See the HTTPExport section for more details.MQTTSecretSendhas been renamed toMQTTExportwith additional parameters. See the MQTTExport section for more details.MarkAsPushedhas been removed. The mark as push capability has been removed from Core Data, which this depended on.MQTTSendhas been removed. This has been replaced byMQTTExport. See the MQTTExport section for more details.FilterByProfileNameandFilterBySourceNamehave been added. See the FilterByProfileName and FilterBySourceName sections for more details.- Ability to define multiple instances of the same Configurable Pipeline Function has been added. See the Multiple Instances of Function section for more details.