Skip to content

Commit 0ff7b16

Browse files
authored
Add support for managing app-scoped egress IPs (#199)
1 parent fcd326d commit 0ff7b16

File tree

3 files changed

+134
-6
lines changed

3 files changed

+134
-6
lines changed

resource_ip_addresses.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ func (c *Client) GetEgressIPAddresses(ctx context.Context, appName string) (map[
151151
ip
152152
version
153153
region
154+
updatedAt
154155
}
155156
}
156157
}
@@ -227,3 +228,86 @@ func (c *Client) ReleaseIPAddress(ctx context.Context, appName string, ip string
227228

228229
return nil
229230
}
231+
232+
func (c *Client) GetAppScopedEgressIPAddresses(ctx context.Context, appName string) (map[string][]EgressIPAddress, error) {
233+
query := `
234+
query ($appName: String!) {
235+
app(name: $appName) {
236+
egressIpAddresses {
237+
nodes {
238+
id
239+
ip
240+
version
241+
region
242+
updatedAt
243+
}
244+
}
245+
}
246+
}
247+
`
248+
249+
req := c.NewRequest(query)
250+
ctx = ctxWithAction(ctx, "get_app_scoped_egress_ip_addresses")
251+
req.Var("appName", appName)
252+
253+
data, err := c.RunWithContext(ctx, req)
254+
if err != nil {
255+
return nil, err
256+
}
257+
258+
ret := make(map[string][]EgressIPAddress)
259+
for _, ip := range data.App.EgressIpAddresses.Nodes {
260+
if _, ok := ret[ip.Region]; !ok {
261+
ret[ip.Region] = make([]EgressIPAddress, 0)
262+
}
263+
264+
ret[ip.Region] = append(ret[ip.Region], *ip)
265+
}
266+
267+
return ret, nil
268+
}
269+
270+
func (c *Client) AllocateAppScopedEgressIPAddress(ctx context.Context, appName string, region string) (net.IP, net.IP, error) {
271+
query := `
272+
mutation($input: AllocateEgressIPAddressInput!) {
273+
allocateEgressIpAddress(input: $input) {
274+
v4,
275+
v6
276+
}
277+
}
278+
`
279+
280+
req := c.NewRequest(query)
281+
ctx = ctxWithAction(ctx, "allocate_app_scoped_egress_ip_address")
282+
req.Var("input", AllocateEgressIPAddressInput{AppID: appName, Region: region})
283+
284+
data, err := c.RunWithContext(ctx, req)
285+
if err != nil {
286+
return nil, nil, err
287+
}
288+
289+
return net.ParseIP(data.AllocateEgressIPAddress.V4), net.ParseIP(data.AllocateEgressIPAddress.V6), nil
290+
}
291+
292+
func (c *Client) ReleaseAppScopedEgressIPAddress(ctx context.Context, appName, ip string) error {
293+
query := `
294+
mutation($input: ReleaseEgressIPAddressInput!) {
295+
releaseEgressIpAddress(input: $input) {
296+
v4
297+
v6
298+
clientMutationId
299+
}
300+
}
301+
`
302+
303+
req := c.NewRequest(query)
304+
ctx = ctxWithAction(ctx, "release_app_scoped_egress_ip_address")
305+
req.Var("input", ReleaseEgressIPAddressInput{AppID: appName, IP: ip})
306+
307+
_, err := c.RunWithContext(ctx, req)
308+
if err != nil {
309+
return err
310+
}
311+
312+
return nil
313+
}

schema.graphql

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,12 @@ input AllocateEgressIPAddressInput {
514514
"""
515515
ID of the machine
516516
"""
517-
machineId: ID!
517+
machineId: ID
518+
519+
"""
520+
If set, allocate an app-scoped egress IP (instead of machine-scoped) in the region
521+
"""
522+
region: String
518523
}
519524

520525
"""
@@ -865,6 +870,27 @@ type App implements Node {
865870
Find a deployment by id, defaults to latest
866871
"""
867872
deploymentStatus(evaluationId: String, id: ID): DeploymentStatus
873+
egressIpAddresses(
874+
"""
875+
Returns the elements in the list that come after the specified cursor.
876+
"""
877+
after: String
878+
879+
"""
880+
Returns the elements in the list that come before the specified cursor.
881+
"""
882+
before: String
883+
884+
"""
885+
Returns the first _n_ elements from the list.
886+
"""
887+
first: Int
888+
889+
"""
890+
Returns the last _n_ elements from the list.
891+
"""
892+
last: Int
893+
): EgressIPAddressConnection!
868894

869895
"""
870896
Check if this app has a configured deployment source
@@ -3435,6 +3461,7 @@ input CreateUserSignupInput {
34353461
clientMutationId: String
34363462

34373463
"""
3464+
34383465
"""
34393466
path: [String!]
34403467

@@ -4323,6 +4350,8 @@ type DummyWireGuardPeerPayload {
43234350
}
43244351

43254352
type EgressIPAddress implements Node {
4353+
createdAt: ISO8601DateTime!
4354+
43264355
"""
43274356
ID of the object.
43284357
"""
@@ -8374,10 +8403,15 @@ input ReleaseEgressIPAddressInput {
83748403
"""
83758404
clientMutationId: String
83768405

8406+
"""
8407+
The IP address to release (in the case of app-scoped egress IPs)
8408+
"""
8409+
ip: String
8410+
83778411
"""
83788412
The ID of the machine
83798413
"""
8380-
machineId: ID!
8414+
machineId: ID
83818415
}
83828416

83838417
"""

types.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ type App struct {
245245
IPAddresses struct {
246246
Nodes []IPAddress
247247
}
248+
EgressIpAddresses struct {
249+
Nodes []*EgressIPAddress
250+
}
248251
SharedIPAddress string
249252
CNAMETarget string
250253
IPAddress *IPAddress
@@ -482,10 +485,11 @@ type IPAddress struct {
482485
}
483486

484487
type EgressIPAddress struct {
485-
ID string
486-
IP string
487-
Version int
488-
Region string
488+
ID string
489+
IP string
490+
Version int
491+
Region string
492+
UpdatedAt time.Time
489493
}
490494

491495
type VMSize struct {
@@ -698,11 +702,17 @@ type AllocateIPAddressInput struct {
698702
type AllocateEgressIPAddressInput struct {
699703
AppID string `json:"appId"`
700704
MachineID string `json:"machineId"`
705+
// If set, allocates an app-scoped egress IP in the region
706+
// Note that region cannot be set simultaneously with machine ID
707+
Region string `json:"region"`
701708
}
702709

703710
type ReleaseEgressIPAddressInput struct {
704711
AppID string `json:"appId"`
705712
MachineID string `json:"machineId"`
713+
// If set, releases the specified app-scoped egress IP
714+
// Note that this cannot be set simultaneously with machine ID
715+
IP string `json:"ip"`
706716
}
707717

708718
type ReleaseIPAddressInput struct {

0 commit comments

Comments
 (0)