Skip to content

Commit 693a8c6

Browse files
authored
New detailed and updated guide for the salesforce source. (#403)
1 parent 7afcc01 commit 693a8c6

22 files changed

+345
-66
lines changed
80.3 KB
Loading
Loading
Loading
Loading
Loading
Loading
51.9 KB
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Binary file not shown.
Binary file not shown.
+341
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
2+
# Ingesting Salesforce change data capture events into TriggerMesh
3+
4+
## Create a Salesforce application
5+
6+
First off, you can now easily create free development accounts in Salesforce to test features like the API for building applications. You can [sign up here](https://developer.salesforce.com/signup).
7+
8+
The TriggerMesh Salesforce source uses [OAuth JWT credentials][salesforce-oauth-jwt] for service authentication. To quote the Salesforce documentation: "This flow uses a certificate to sign the JWT request and doesn’t require explicit user interaction. However, this flow does require prior approval of the client app."
9+
10+
1. First, you will need to generate an X509 certificate for signing and verifying requests.
11+
We will be using `OpenSSL` but any other certificate generation tool should work.
12+
13+
```sh
14+
openssl req -x509 -sha256 -nodes -days 36500 -newkey rsa:2048 -keyout tm-sf.key -out tm-sf.crt
15+
```
16+
17+
2. At Salesforce site select `Setup > Apps > App Manager`, click on `New Connected App`.
18+
19+
![Setup](../../assets/images/salesforce-source/1-setup.png)
20+
21+
![New Connected App](../../assets/images/salesforce-source/2-connectedapp.png)
22+
23+
- Fill in mandatory fields, then click `Enable OAuth Settings`.
24+
- A callback URL is mandatory but can be filled with any HTTPS data.
25+
- Enable `Use digital signatures` and upload the public cert (`tm-sf.crt` in the example above).
26+
- Add Scopes for `api` and `refresh_token, offline_access`.
27+
- Save
28+
29+
![Salesforce connected app](../../assets/images/salesforce-source/3-configureapp.png)
30+
31+
- Click on `Manage`.
32+
- Click `Edit policies`.
33+
- Set Permitted users to `Admin approved users are pre-authorized`.
34+
- Save.
35+
36+
![Click manage](../../assets/images/salesforce-source/4-clickmanage.png)
37+
38+
![Click edit policies](../../assets/images/salesforce-source/5-clickeditpolicies.png)
39+
40+
![Permitted users](../../assets/images/salesforce-source/6-permittedusers.png)
41+
42+
- From further down on the same page, click `Manage Profiles`.
43+
- Select the profiles that should be allowed to use this application. In our example, when creating a Salesforce developer account, we're assigned the profile `System Administrator`. This is the same user we'll be using to authenticate our TriggerMesh Salesforce source to the Salesforce API. So for now, we'll only add the `System Administrator` profile.
44+
- Save
45+
46+
![Click manage profiles](../../assets/images/salesforce-source/7-clickmanageprofiles.png)
47+
![Add System Administrator](../../assets/images/salesforce-source/7bis-addsysadmin.png)
48+
49+
3. Retrieve OAuth data to configure TriggerMesh Source.
50+
51+
- Head back to the list of apps, open the drop-down next to your app and click on `View`.
52+
- Click on `Manage Consumer Details`. You might need to enter an email verification code in a new window
53+
- Copy the `Consumer Key` and save it somewhere handy. You won't need the secret because we're using the previously generated certificate to authenticate.
54+
55+
![View app](../../assets/images/salesforce-source/8-viewapp.png)
56+
![Manage consumer details](../../assets/images/salesforce-source/9-consumerdetails.png)
57+
![Enter verification code](../../assets/images/salesforce-source/10-verificationcode.png)
58+
![Copy consumer key](../../assets/images/salesforce-source/11-copykey.png)
59+
60+
4. Configure the Change Data Capture events that you want to react to
61+
62+
There are a number of different "stream channels" that you can use:
63+
64+
- Change Data Capture events: `/data/ChangeEvents`
65+
- PushTopics for streams based on single entity SOQL queries: `/topic/TicketsSold`
66+
- Standard Platform Events for Salesforce event monitoring: `/event/LoginEventStream`
67+
- Custom Platform Events for your SOQL platform events: `/event/MyCustom__e`
68+
69+
Each Streaming event type has a distinct [set of features][salesroce-event-features]. Please refer to [Salesforce stream API][salesforce-stream-api-docs] on how to create stream channels.
70+
71+
In this example we're going to use change data capture events to track changes to important sales resources such as accounts, cases, and opportunities.
72+
73+
Head to `Setup > Integrations > Change Data Capture` and enable CDC notifications for the types of objects you're interested in, such as `Account`, `Opportunity`, and `Case`.
74+
75+
![Configure CDC](../../assets/images/salesforce-source/12-cdc.png)
76+
77+
Your Salesforce app is now configured and you can start ingesting events into TriggerMesh.
78+
79+
## Ingest Salesforce events into TriggerMesh
80+
81+
If you want, you can create a dedicated namespace for this TriggerMesh integration:
82+
83+
```sh
84+
kubectl create namespace sfdc-to-redpanda
85+
```
86+
87+
We'll start by creating a TriggerMesh Broker that will decouple event producers and consumers and provide a reliable, push-based event delivery pipeline. Create a file called `broker-v1.yaml` with the following content:
88+
89+
```yaml
90+
apiVersion: eventing.triggermesh.io/v1alpha1
91+
kind: RedisBroker
92+
metadata:
93+
name: triggermesh-redis-broker
94+
namespace: sfdc-to-redpanda
95+
```
96+
97+
Create the broker:
98+
99+
```sh
100+
kubectl apply -f broker-v1.yaml
101+
```
102+
103+
Now we can create a secret that will contain the Salesforce key we created earlier. Create a file called `salesforce-cert-secret.yaml` and enter the secret's configuration:
104+
105+
```yaml
106+
apiVersion: v1
107+
kind: Secret
108+
metadata:
109+
name: salesforce
110+
namespace: sfdc-to-redpanda
111+
type: Opaque
112+
stringData:
113+
certKey: |-
114+
-----BEGIN PRIVATE KEY-----
115+
MIIEvAIBADANB
116+
...
117+
6GRQtbkMCfBd7V4GmIXjdg==
118+
-----END PRIVATE KEY-----
119+
```
120+
121+
Create the secret:
122+
123+
```sh
124+
kubectl apply -f salesforce-cert-secret.yaml
125+
```
126+
127+
And we can also create the salesforce source itself. Use the email address that corresponds to the user name of the account you created on Salesforce developers. Create a file called `salesforce-source-v1.yaml` and save it with the following contents:
128+
129+
```yaml
130+
apiVersion: sources.triggermesh.io/v1alpha1
131+
kind: SalesforceSource
132+
metadata:
133+
name: salesforce-source
134+
namespace: sfdc-to-redpanda
135+
spec:
136+
subscription:
137+
channel: /data/ChangeEvents
138+
replayID: -2
139+
140+
auth:
141+
clientID: <your consumer key, e.g. 3MVG9OvGYd.....>
142+
user: <your Salesforce user login email, e.g. [email protected]>
143+
server: https://login.salesforce.com
144+
certKey:
145+
valueFromSecret:
146+
name: salesforce
147+
key: certKey
148+
sink:
149+
ref:
150+
apiVersion: eventing.triggermesh.io/v1alpha1
151+
kind: RedisBroker
152+
name: triggermesh-redis-broker
153+
```
154+
155+
Create the source:
156+
157+
```sh
158+
kubectl apply -f salesforce-source-v1.yaml
159+
```
160+
161+
To make sure this first ingestion step is working, we'll create an event display service that logs all CloudEvents it receives, and send this service a copy of all events passing through the broker. This pattern is also known as a wiretap.
162+
163+
Create a file called `event-display-wiretap.yaml` with the following contents:
164+
165+
```yaml
166+
apiVersion: apps/v1
167+
kind: Deployment
168+
metadata:
169+
name: event-display
170+
namespace: sfdc-to-redpanda
171+
spec:
172+
replicas: 1
173+
selector:
174+
matchLabels: &labels
175+
app: event-display
176+
template:
177+
metadata:
178+
labels: *labels
179+
spec:
180+
containers:
181+
- name: event-display
182+
image: gcr.io/knative-releases/knative.dev/eventing/cmd/event_display
183+
184+
---
185+
186+
kind: Service
187+
apiVersion: v1
188+
metadata:
189+
name: event-display
190+
namespace: sfdc-to-redpanda
191+
spec:
192+
selector:
193+
app: event-display
194+
ports:
195+
- protocol: TCP
196+
port: 80
197+
targetPort: 8080
198+
199+
---
200+
201+
apiVersion: eventing.triggermesh.io/v1alpha1
202+
kind: Trigger
203+
metadata:
204+
name: event-display-trigger
205+
namespace: sfdc-to-redpanda
206+
spec:
207+
broker:
208+
group: eventing.triggermesh.io
209+
kind: RedisBroker
210+
name: triggermesh-redis-broker
211+
target:
212+
ref:
213+
apiVersion: v1
214+
kind: Service
215+
name: event-display
216+
```
217+
218+
Create the wiretap:
219+
220+
```sh
221+
kubectl apply -f event-display-wiretap.yaml
222+
```
223+
224+
In a new window, watch the logs from the event display service:
225+
226+
```sh
227+
kubectl get pods
228+
NAME READY STATUS RESTARTS AGE
229+
event-display-6994b6cc4c-fvq8w 1/1 Running 0 30s
230+
salesforcesource-salesforce-source-847ff57bd8-ghsfk 1/1 Running 0 12m
231+
triggermesh-redis-broker-rb-broker-74ff75d48d-rsbfc 1/1 Running 0 26m
232+
triggermesh-redis-broker-rb-redis-778b9c8fb4-lhskm 1/1 Running 0 27m
233+
```
234+
235+
```sh
236+
kubectl logs -f event-display-6994b6cc4c-fvq8w
237+
```
238+
239+
Create a new account in Salesforce, and you should see a new change event appear in the event display logs.
240+
241+
To do this, first head to the accounts page, for example by first heading to `View all` then selecting `Accounts`:
242+
243+
![View all](../../assets/images/salesforce-source/13-viewall.png)
244+
245+
![Accounts](../../assets/images/salesforce-source/14-accounts.png)
246+
247+
Then create a new account, for example with the name `Redpanda`:
248+
249+
![New account](../../assets/images/salesforce-source/15-new.png)
250+
251+
![New Redpanda account](../../assets/images/salesforce-source/16-redpanda.png)
252+
253+
Save the new account, and then check your event display logs. You should see a new change event indicating that a new `Account` named `Redpanda` was created:
254+
255+
```sh
256+
☁️ cloudevents.Event
257+
Context Attributes,
258+
specversion: 1.0
259+
type: com.salesforce.stream.message
260+
source: salesforce-source/data/ChangeEvents
261+
subject: Account/CREATE
262+
id: 192ff6d1-e15f-4767-89da-c9644eec8f5c
263+
time: 2023-07-18T14:15:27.532305888Z
264+
datacontenttype: application/json
265+
Data,
266+
{
267+
"event": {
268+
"createdDate": "0001-01-01T00:00:00Z",
269+
"replayId": 31641490
270+
},
271+
"schema": "JPyUm_b7b4SSjXobT5DOPg",
272+
"payload": {
273+
"LastModifiedDate": "2023-07-18T14:15:24.000Z",
274+
"Name": "Redpanda",
275+
"OwnerId": "0050600000H0tB5AAJ",
276+
"CreatedById": "0050600000H0tB5AAJ",
277+
"CleanStatus": "Pending",
278+
"ChangeEventHeader": {
279+
"commitNumber": 11696120723556,
280+
"commitUser": "0050600000H0tB5AAJ",
281+
"sequenceNumber": 1,
282+
"entityName": "Account",
283+
"changeType": "CREATE",
284+
"changedFields": [],
285+
"changeOrigin": "com/salesforce/api/soap/58.0;client=SfdcInternalAPI/",
286+
"transactionKey": "0000d388-e8a0-4796-9944-732b3a99a31d",
287+
"commitTimestamp": 1689689724000,
288+
"recordIds": [
289+
"00106000029G61DAAS"
290+
]
291+
},
292+
"CreatedDate": "2023-07-18T14:15:24.000Z",
293+
"LastModifiedById": "0050600000H0tB5AAJ"
294+
}
295+
}
296+
```
297+
298+
You'll notice that this Salesforce CDC event is wrapped into a CloudEvent, which is the native event envelope used by TriggerMesh. It includes `Context Attributes` that can be useful for routing events.
299+
300+
If we now update this account, for example by updating the account's Rating to `Hot`, we'll see an update notification:
301+
302+
```sh
303+
☁️ cloudevents.Event
304+
Context Attributes,
305+
specversion: 1.0
306+
type: com.salesforce.stream.message
307+
source: salesforce-source/data/ChangeEvents
308+
subject: Account/UPDATE
309+
id: 6833266d-417a-49c4-b40e-d76676f5d5d1
310+
time: 2023-07-18T14:46:51.150001926Z
311+
datacontenttype: application/json
312+
Data,
313+
{
314+
"event": {
315+
"createdDate": "0001-01-01T00:00:00Z",
316+
"replayId": 31641494
317+
},
318+
"schema": "JPyUm_b7b4SSjXobT5DOPg",
319+
"payload": {
320+
"LastModifiedDate": "2023-07-18T14:46:50.000Z",
321+
"Rating": "Hot",
322+
"ChangeEventHeader": {
323+
"commitNumber": 11696145023574,
324+
"commitUser": "0050600000H0tB5AAJ",
325+
"sequenceNumber": 1,
326+
"entityName": "Account",
327+
"changeType": "UPDATE",
328+
"changedFields": [
329+
"Rating",
330+
"LastModifiedDate"
331+
],
332+
"changeOrigin": "com/salesforce/api/soap/58.0;client=SfdcInternalAPI/",
333+
"transactionKey": "000171b6-1688-feb9-f59e-bb0dbfe74dbc",
334+
"commitTimestamp": 1689691610000,
335+
"recordIds": [
336+
"00106000029G61DAAS"
337+
]
338+
}
339+
}
340+
}
341+
```

0 commit comments

Comments
 (0)