Skip to content

Commit db59070

Browse files
authored
Merge pull request #948 from EngHabu/tunnel-config-update
Add UpdateTunnelConfiguration func
2 parents e867ac2 + fc41da1 commit db59070

File tree

2 files changed

+323
-7
lines changed

2 files changed

+323
-7
lines changed

tunnel.go

Lines changed: 203 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import (
1010
"github.com/pkg/errors"
1111
)
1212

13+
// ErrMissingTunnelID is for when a required tunnel ID is missing from the
14+
// parameters.
15+
var ErrMissingTunnelID = errors.New("required missing tunnel ID")
16+
1317
// Tunnel is the struct definition of a tunnel.
1418
type Tunnel struct {
1519
ID string `json:"id,omitempty"`
@@ -47,6 +51,34 @@ type TunnelDetailResponse struct {
4751
Response
4852
}
4953

54+
// TunnelConfigurationStringifiedConfigResult is the raw result from the API with
55+
// the `Config` value as a string. You probably don't want to use this anywhere
56+
// other than in the HTTP response unmarshaling. Use `TunnelConfigurationResult`
57+
// for the correct types.
58+
type TunnelConfigurationStringifiedConfigResult struct {
59+
TunnelID string `json:"tunnel_id,omitempty"`
60+
Config string `json:"config,omitempty"`
61+
Version int `json:"version,omitempty"`
62+
}
63+
64+
type TunnelConfigurationStringifiedConfigResponse struct {
65+
Result TunnelConfigurationStringifiedConfigResult `json:"result"`
66+
Response
67+
}
68+
69+
type TunnelConfigurationResult struct {
70+
TunnelID string `json:"tunnel_id,omitempty"`
71+
Config TunnelConfiguration `json:"config,omitempty"`
72+
Version int `json:"version,omitempty"`
73+
}
74+
75+
// TunnelConfigurationResponse is used for representing the API response payload
76+
// for a single tunnel.
77+
type TunnelConfigurationResponse struct {
78+
Result TunnelConfigurationResult `json:"result"`
79+
Response
80+
}
81+
5082
// TunnelTokenResponse is the API response for a tunnel token.
5183
type TunnelTokenResponse struct {
5284
Result string `json:"result"`
@@ -70,6 +102,82 @@ type TunnelUpdateParams struct {
70102
Secret string `json:"tunnel_secret,omitempty"`
71103
}
72104

105+
type UnvalidatedIngressRule struct {
106+
Hostname string `json:"hostname,omitempty"`
107+
Path string `json:"path,omitempty"`
108+
Service string `json:"service,omitempty"`
109+
}
110+
111+
// OriginRequestConfig is a set of optional fields that users may set to
112+
// customize how cloudflared sends requests to origin services. It is used to set
113+
// up general config that apply to all rules, and also, specific per-rule
114+
// config.
115+
type OriginRequestConfig struct {
116+
// HTTP proxy timeout for establishing a new connection
117+
ConnectTimeout *time.Duration `json:"connectTimeout,omitempty"`
118+
// HTTP proxy timeout for completing a TLS handshake
119+
TLSTimeout *time.Duration `json:"tlsTimeout,omitempty"`
120+
// HTTP proxy TCP keepalive duration
121+
TCPKeepAlive *time.Duration `json:"tcpKeepAlive,omitempty"`
122+
// HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
123+
NoHappyEyeballs *bool `json:"noHappyEyeballs,omitempty"`
124+
// HTTP proxy maximum keepalive connection pool size
125+
KeepAliveConnections *int `json:"keepAliveConnections,omitempty"`
126+
// HTTP proxy timeout for closing an idle connection
127+
KeepAliveTimeout *time.Duration `json:"keepAliveTimeout,omitempty"`
128+
// Sets the HTTP Host header for the local webserver.
129+
HTTPHostHeader *string `json:"httpHostHeader,omitempty"`
130+
// Hostname on the origin server certificate.
131+
OriginServerName *string `json:"originServerName,omitempty"`
132+
// Path to the CA for the certificate of your origin.
133+
// This option should be used only if your certificate is not signed by Cloudflare.
134+
CAPool *string `json:"caPool,omitempty"`
135+
// Disables TLS verification of the certificate presented by your origin.
136+
// Will allow any certificate from the origin to be accepted.
137+
// Note: The connection from your machine to Cloudflare's Edge is still encrypted.
138+
NoTLSVerify *bool `json:"noTLSVerify,omitempty"`
139+
// Disables chunked transfer encoding.
140+
// Useful if you are running a WSGI server.
141+
DisableChunkedEncoding *bool `json:"disableChunkedEncoding,omitempty"`
142+
// Runs as jump host
143+
BastionMode *bool `json:"bastionMode,omitempty"`
144+
// Listen address for the proxy.
145+
ProxyAddress *string `json:"proxyAddress,omitempty"`
146+
// Listen port for the proxy.
147+
ProxyPort *uint `json:"proxyPort,omitempty"`
148+
// Valid options are 'socks' or empty.
149+
ProxyType *string `json:"proxyType,omitempty"`
150+
// IP rules for the proxy service
151+
IPRules []IngressIPRule `json:"ipRules,omitempty"`
152+
}
153+
154+
type IngressIPRule struct {
155+
Prefix *string `json:"prefix,omitempty"`
156+
Ports []int `json:"ports,omitempty"`
157+
Allow bool `json:"allow,omitempty"`
158+
}
159+
160+
type TunnelConfiguration struct {
161+
Ingress []UnvalidatedIngressRule `json:"ingress,omitempty"`
162+
WarpRouting *WarpRoutingConfig `json:"warp-routing,omitempty"`
163+
OriginRequest OriginRequestConfig `json:"originRequest,omitempty"`
164+
}
165+
166+
type WarpRoutingConfig struct {
167+
Enabled bool `json:"enabled,omitempty"`
168+
}
169+
170+
type TunnelConfigurationParams struct {
171+
AccountID string `json:"-"`
172+
TunnelID string `json:"-"`
173+
Config TunnelConfiguration `json:"config,omitempty"`
174+
}
175+
176+
type GetTunnelConfigurationParams struct {
177+
AccountID string `json:"-"`
178+
TunnelID string `json:"-"`
179+
}
180+
73181
type TunnelDeleteParams struct {
74182
AccountID string
75183
ID string
@@ -103,7 +211,7 @@ func (api *API) Tunnels(ctx context.Context, params TunnelListParams) ([]Tunnel,
103211

104212
uri := buildURI(fmt.Sprintf("/accounts/%s/cfd_tunnel", params.AccountID), params)
105213

106-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodGet, uri, nil, nil)
214+
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
107215
if err != nil {
108216
return []Tunnel{}, err
109217
}
@@ -130,7 +238,7 @@ func (api *API) Tunnel(ctx context.Context, params TunnelParams) (Tunnel, error)
130238

131239
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s", params.AccountID, params.ID)
132240

133-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodGet, uri, nil, nil)
241+
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
134242
if err != nil {
135243
return Tunnel{}, err
136244
}
@@ -163,7 +271,7 @@ func (api *API) CreateTunnel(ctx context.Context, params TunnelCreateParams) (Tu
163271

164272
tunnel := Tunnel{Name: params.Name, Secret: params.Secret}
165273

166-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPost, uri, tunnel, nil)
274+
res, err := api.makeRequestContext(ctx, http.MethodPost, uri, tunnel)
167275
if err != nil {
168276
return Tunnel{}, err
169277
}
@@ -197,7 +305,7 @@ func (api *API) UpdateTunnel(ctx context.Context, params TunnelUpdateParams) (Tu
197305
tunnel.Secret = params.Secret
198306
}
199307

200-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPatch, uri, tunnel, nil)
308+
res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, tunnel)
201309
if err != nil {
202310
return Tunnel{}, err
203311
}
@@ -211,13 +319,101 @@ func (api *API) UpdateTunnel(ctx context.Context, params TunnelUpdateParams) (Tu
211319
return argoDetailsResponse.Result, nil
212320
}
213321

322+
// UpdateTunnelConfiguration updates an existing tunnel for the account.
323+
//
324+
// API reference: https://api.cloudflare.com/#cloudflare-tunnel-configuration-properties
325+
func (api *API) UpdateTunnelConfiguration(ctx context.Context, params TunnelConfigurationParams) (TunnelConfigurationResult, error) {
326+
if len(params.AccountID) == 0 {
327+
return TunnelConfigurationResult{}, ErrMissingAccountID
328+
}
329+
330+
if len(params.TunnelID) == 0 {
331+
return TunnelConfigurationResult{}, ErrMissingTunnelID
332+
}
333+
334+
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/configurations", params.AccountID, params.TunnelID)
335+
res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params.Config)
336+
if err != nil {
337+
return TunnelConfigurationResult{}, err
338+
}
339+
340+
// `config` comes back as a stringified representation of the configuration
341+
// so we need to double unmarshal the result. First, `config` => the string
342+
// struct field and if that is successful, then attempt putting it into a typed
343+
// struct field.
344+
345+
var tunnelDetailsResponse TunnelConfigurationStringifiedConfigResponse
346+
err = json.Unmarshal(res, &tunnelDetailsResponse)
347+
if err != nil {
348+
return TunnelConfigurationResult{}, errors.Wrap(err, errUnmarshalError)
349+
}
350+
351+
var tunnelDetails TunnelConfigurationResult
352+
var tunnelConfig TunnelConfiguration
353+
354+
err = json.Unmarshal([]byte(tunnelDetailsResponse.Result.Config), &tunnelConfig)
355+
if err != nil {
356+
return TunnelConfigurationResult{}, errors.Wrap(err, errUnmarshalError)
357+
}
358+
359+
tunnelDetails.Config = tunnelConfig
360+
tunnelDetails.TunnelID = tunnelDetailsResponse.Result.TunnelID
361+
tunnelDetails.Version = tunnelDetailsResponse.Result.Version
362+
363+
return tunnelDetails, nil
364+
}
365+
366+
// GetTunnelConfiguration updates an existing tunnel for the account.
367+
//
368+
// API reference: https://api.cloudflare.com/#cloudflare-tunnel-configuration-properties
369+
func (api *API) GetTunnelConfiguration(ctx context.Context, params GetTunnelConfigurationParams) (TunnelConfigurationResult, error) {
370+
if len(params.AccountID) == 0 {
371+
return TunnelConfigurationResult{}, ErrMissingAccountID
372+
}
373+
374+
if len(params.TunnelID) == 0 {
375+
return TunnelConfigurationResult{}, ErrMissingTunnelID
376+
}
377+
378+
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/configurations", params.AccountID, params.TunnelID)
379+
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
380+
if err != nil {
381+
return TunnelConfigurationResult{}, err
382+
}
383+
384+
// `config` comes back as a stringified representation of the configuration
385+
// so we need to double unmarshal the result. First, `config` => the string
386+
// struct field and if that is successful, then attempt putting it into a typed
387+
// struct field.
388+
389+
var tunnelDetailsResponse TunnelConfigurationStringifiedConfigResponse
390+
err = json.Unmarshal(res, &tunnelDetailsResponse)
391+
if err != nil {
392+
return TunnelConfigurationResult{}, errors.Wrap(err, errUnmarshalError)
393+
}
394+
395+
var tunnelDetails TunnelConfigurationResult
396+
var tunnelConfig TunnelConfiguration
397+
398+
err = json.Unmarshal([]byte(tunnelDetailsResponse.Result.Config), &tunnelConfig)
399+
if err != nil {
400+
return TunnelConfigurationResult{}, errors.Wrap(err, errUnmarshalError)
401+
}
402+
403+
tunnelDetails.Config = tunnelConfig
404+
tunnelDetails.TunnelID = tunnelDetailsResponse.Result.TunnelID
405+
tunnelDetails.Version = tunnelDetailsResponse.Result.Version
406+
407+
return tunnelDetails, nil
408+
}
409+
214410
// DeleteTunnel removes a single Argo tunnel.
215411
//
216412
// API reference: https://api.cloudflare.com/#cloudflare-tunnel-delete-cloudflare-tunnel
217413
func (api *API) DeleteTunnel(ctx context.Context, params TunnelDeleteParams) error {
218414
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s", params.AccountID, params.ID)
219415

220-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodDelete, uri, nil, nil)
416+
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
221417
if err != nil {
222418
return err
223419
}
@@ -245,7 +441,7 @@ func (api *API) CleanupTunnelConnections(ctx context.Context, params TunnelClean
245441

246442
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/connections", params.AccountID, params.ID)
247443

248-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodDelete, uri, nil, nil)
444+
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
249445
if err != nil {
250446
return err
251447
}
@@ -273,7 +469,7 @@ func (api *API) TunnelToken(ctx context.Context, params TunnelTokenParams) (stri
273469

274470
uri := fmt.Sprintf("/accounts/%s/cfd_tunnel/%s/token", params.AccountID, params.ID)
275471

276-
res, err := api.makeRequestContextWithHeaders(ctx, http.MethodGet, uri, nil, nil)
472+
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
277473
if err != nil {
278474
return "", err
279475
}

0 commit comments

Comments
 (0)