@@ -12,13 +12,60 @@ use crate::Generation;
12
12
use crate :: WebhookDelivery ;
13
13
use chrono:: { DateTime , Utc } ;
14
14
use db_macros:: Resource ;
15
+ use nexus_types:: external_api:: views;
15
16
use omicron_common:: api:: external:: Error ;
16
- use omicron_uuid_kinds:: { WebhookReceiverKind , WebhookReceiverUuid } ;
17
+ use omicron_uuid_kinds:: {
18
+ WebhookReceiverKind , WebhookReceiverUuid , WebhookSecretKind ,
19
+ WebhookSecretUuid ,
20
+ } ;
17
21
use serde:: { Deserialize , Serialize } ;
18
22
use std:: str:: FromStr ;
19
23
use uuid:: Uuid ;
20
24
21
- /// A webhook receiver configuration.
25
+ /// The full configuration of a webhook receiver, including the
26
+ /// [`WebhookReceiver`] itself and its subscriptions and secrets.
27
+ pub struct WebhookReceiverConfig {
28
+ pub rx : WebhookReceiver ,
29
+ pub secrets : Vec < WebhookRxSecret > ,
30
+ pub events : Vec < WebhookSubscriptionKind > ,
31
+ }
32
+
33
+ impl TryFrom < WebhookReceiverConfig > for views:: Webhook {
34
+ type Error = Error ;
35
+ fn try_from (
36
+ WebhookReceiverConfig { rx, secrets, events } : WebhookReceiverConfig ,
37
+ ) -> Result < views:: Webhook , Self :: Error > {
38
+ let secrets = secrets
39
+ . iter ( )
40
+ . map ( |WebhookRxSecret { signature_id, .. } | {
41
+ views:: WebhookSecretId { id : signature_id. to_string ( ) }
42
+ } )
43
+ . collect ( ) ;
44
+ let events = events
45
+ . into_iter ( )
46
+ . map ( WebhookSubscriptionKind :: into_event_class_string)
47
+ . collect ( ) ;
48
+ let WebhookReceiver { identity, endpoint, probes_enabled, rcgen : _ } =
49
+ rx;
50
+ let WebhookReceiverIdentity { id, name, description, .. } = identity;
51
+ let endpoint = endpoint. parse ( ) . map_err ( |e| Error :: InternalError {
52
+ // This is an internal error, as we should not have ever allowed
53
+ // an invalid URL to be inserted into the database...
54
+ internal_message : format ! ( "invalid webhook URL {endpoint:?}: {e}" , ) ,
55
+ } ) ?;
56
+ Ok ( views:: Webhook {
57
+ id : id. into ( ) ,
58
+ name : name. to_string ( ) ,
59
+ description,
60
+ endpoint,
61
+ secrets,
62
+ events,
63
+ disable_probes : !probes_enabled,
64
+ } )
65
+ }
66
+ }
67
+
68
+ /// A row in the `webhook_rx` table.
22
69
#[ derive(
23
70
Clone ,
24
71
Debug ,
@@ -78,12 +125,24 @@ impl DatastoreCollectionConfig<WebhookDelivery> for WebhookReceiver {
78
125
#[ diesel( table_name = webhook_rx_secret) ]
79
126
pub struct WebhookRxSecret {
80
127
pub rx_id : DbTypedUuid < WebhookReceiverKind > ,
81
- pub signature_id : String ,
82
- pub secret : Vec < u8 > ,
128
+ pub signature_id : DbTypedUuid < WebhookSecretKind > ,
129
+ pub secret : String ,
83
130
pub time_created : DateTime < Utc > ,
84
131
pub time_deleted : Option < DateTime < Utc > > ,
85
132
}
86
133
134
+ impl WebhookRxSecret {
135
+ pub fn new ( rx_id : WebhookReceiverUuid , secret : String ) -> Self {
136
+ Self {
137
+ rx_id : rx_id. into ( ) ,
138
+ signature_id : WebhookSecretUuid :: new_v4 ( ) . into ( ) ,
139
+ secret,
140
+ time_created : Utc :: now ( ) ,
141
+ time_deleted : None ,
142
+ }
143
+ }
144
+ }
145
+
87
146
#[ derive(
88
147
Clone , Debug , Queryable , Selectable , Insertable , Serialize , Deserialize ,
89
148
) ]
@@ -132,6 +191,13 @@ impl WebhookSubscriptionKind {
132
191
Ok ( Self :: Exact ( value) )
133
192
}
134
193
}
194
+
195
+ fn into_event_class_string ( self ) -> String {
196
+ match self {
197
+ Self :: Exact ( class) => class,
198
+ Self :: Glob ( WebhookGlob { glob, .. } ) => glob,
199
+ }
200
+ }
135
201
}
136
202
137
203
#[ derive(
0 commit comments