Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
with:
version: v1.54
working-directory: .
skip-pkg-cache: true
skip-cache: true

test:
strategy:
Expand Down
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func (c *Client) RunWithContext(ctx context.Context, req *graphql.Request) (Quer
err := c.client.Run(ctx, req, &resp)

if resp.Errors != nil {
span.RecordError(fmt.Errorf(c.getErrorFromErrors(resp.Errors)))
span.RecordError(errors.New(c.getErrorFromErrors(resp.Errors)))
span.SetStatus(codes.Error, "failed to do grapqhl request")
}

Expand Down
3 changes: 3 additions & 0 deletions flaps/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ const (
metadataDel
regionsGet
placementPost
ipAssignmentsList
ipAssignmentCreate
ipAssignmentDelete
)
70 changes: 70 additions & 0 deletions flaps/flaps_ips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package flaps

import (
"context"
"fmt"
"net/http"
"time"
)

type IPAssignment struct {
CreatedAt time.Time `json:"created_at"`
IP string `json:"ip"`
Region string `json:"region"`
ServiceName string `json:"service_name"`
Shared bool `json:"shared"`
Type string `json:"type,omitempty"`
}

type ListIPAssignmentsResponse struct {
IPs []IPAssignment `json:"ips"`
}

type AssignIPRequest struct {
Type string `json:"type"`
Region string `json:"region,omitempty"`
OrgSlug string `json:"org_slug,omitempty"`
Network string `json:"network,omitempty"`
ServiceName string `json:"service_name,omitempty"`
}

func (f *Client) sendRequestIPAssignments(ctx context.Context, method, endpoint string, in, out interface{}, headers map[string][]string) error {
endpoint = fmt.Sprintf("/apps/%s%s", f.appName, endpoint)
return f._sendRequest(ctx, method, endpoint, in, out, headers)
}

// ListIPAssignments lists all IP assignments for the app
func (f *Client) ListIPAssignments(ctx context.Context) (*ListIPAssignmentsResponse, error) {
ctx = contextWithAction(ctx, ipAssignmentsList)

out := new(ListIPAssignmentsResponse)
if err := f.sendRequestIPAssignments(ctx, http.MethodGet, "/ip_assignments", nil, out, nil); err != nil {
return nil, fmt.Errorf("failed to list IP assignments: %w", err)
}

return out, nil
}

// AssignIPAddress assigns a new IP address to the app
func (f *Client) AssignIPAddress(ctx context.Context, req *AssignIPRequest) (*IPAssignment, error) {
ctx = contextWithAction(ctx, ipAssignmentCreate)

out := new(IPAssignment)
if err := f.sendRequestIPAssignments(ctx, http.MethodPost, "/ip_assignments", req, out, nil); err != nil {
return nil, fmt.Errorf("failed to assign IP address: %w", err)
}

return out, nil
}

// ReleaseIPAddress releases an IP address from the app
func (f *Client) ReleaseIPAddress(ctx context.Context, ip string) error {
ctx = contextWithAction(ctx, ipAssignmentDelete)

endpoint := fmt.Sprintf("/ip_assignments/%s", ip)
if err := f.sendRequestIPAssignments(ctx, http.MethodDelete, endpoint, nil, nil, nil); err != nil {
return fmt.Errorf("failed to release IP address: %w", err)
}

return nil
}
7 changes: 5 additions & 2 deletions flaps/flapsaction_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 97 additions & 0 deletions resource_egress_ips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package fly

import (
"context"
"net"
)

func (c *Client) AllocateEgressIPAddress(ctx context.Context, appName string, machineId string) (net.IP, net.IP, error) {
query := `
mutation($input: AllocateEgressIPAddressInput!) {
allocateEgressIpAddress(input: $input) {
v4,
v6
}
}
`

req := c.NewRequest(query)
ctx = ctxWithAction(ctx, "allocate_egress_ip_address")
req.Var("input", AllocateEgressIPAddressInput{AppID: appName, MachineID: machineId})

data, err := c.RunWithContext(ctx, req)
if err != nil {
return nil, nil, err
}

return net.ParseIP(data.AllocateEgressIPAddress.V4), net.ParseIP(data.AllocateEgressIPAddress.V6), nil
}

func (c *Client) GetEgressIPAddresses(ctx context.Context, appName string) (map[string][]EgressIPAddress, error) {
query := `
query ($appName: String!) {
app(name: $appName) {
machines {
nodes {
id
egressIpAddresses {
nodes {
id
ip
version
region
}
}
}
}
}
}
`

req := c.NewRequest(query)
ctx = ctxWithAction(ctx, "get_egress_ip_addresses")
req.Var("appName", appName)

data, err := c.RunWithContext(ctx, req)
if err != nil {
return nil, err
}

ret := make(map[string][]EgressIPAddress)
for _, m := range data.App.Machines.Nodes {
if len(m.EgressIpAddresses.Nodes) == 0 {
continue
}

ret[m.ID] = make([]EgressIPAddress, len(m.EgressIpAddresses.Nodes))

for i, ip := range m.EgressIpAddresses.Nodes {
ret[m.ID][i] = *ip
}
}

return ret, nil
}

func (c *Client) ReleaseEgressIPAddress(ctx context.Context, appName, machineID string) (net.IP, net.IP, error) {
query := `
mutation($input: ReleaseEgressIPAddressInput!) {
releaseEgressIpAddress(input: $input) {
v4
v6
clientMutationId
}
}
`

req := c.NewRequest(query)
ctx = ctxWithAction(ctx, "release_egress_ip_address")
req.Var("input", ReleaseEgressIPAddressInput{AppID: appName, MachineID: machineID})

data, err := c.RunWithContext(ctx, req)
if err != nil {
return nil, nil, err
}

return net.ParseIP(data.ReleaseEgressIPAddress.V4), net.ParseIP(data.ReleaseEgressIPAddress.V6), nil
}
Loading
Loading