Skip to content
Merged
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
11 changes: 4 additions & 7 deletions cli/cmd/customer_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ func (r *runners) InitCustomersCreateCommand(parent *cobra.Command) *cobra.Comma
SilenceUsage: true,
}
parent.AddCommand(cmd)
cmd.Flags().StringVar(&r.args.customerCreateName, "name", "", "The Customer Name")
cmd.Flags().StringVar(&r.args.customerCreateChannel, "channel", "", "The Customer Channel")
cmd.Flags().DurationVar(&r.args.customerCreateExpiryDuration, "expires-in", 0, "If set, an expiration date will be set on the license")
cmd.Flags().StringVar(&r.args.customerCreateName, "name", "", "Name of the customer")
cmd.Flags().StringVar(&r.args.customerCreateChannel, "channel", "", "Release channel to which the customer should be assigned")
cmd.Flags().DurationVar(&r.args.customerCreateExpiryDuration, "expires-in", 0, "If set, an expiration date will be set on the license. Supports Go durations like '72h' or '3600m'")
cmd.Flags().BoolVar(&r.args.customerCreateEnsureChannel, "ensure-channel", false, "If set, channel will be created if it does not exist.")

return cmd
Expand All @@ -37,13 +37,10 @@ func (r *runners) createCustomer(_ *cobra.Command, _ []string) error {
return errors.Wrap(err, "get channel")
}

customer, err := r.api.CreateCustomer(r.appType, r.args.customerCreateName, channel.ID, r.args.customerCreateExpiryDuration)
customer, err := r.api.CreateCustomer(r.appID, r.appType, r.args.customerCreateName, channel.ID, r.args.customerCreateExpiryDuration)
if err != nil {
return errors.Wrap(err, "create customer")
}

// CreateCustomer query doesn't pull back the Channels, so bolt it on afterward for the printing
customer.Channels = append(customer.Channels, *channel)

return print.Customers(r.w, []types.Customer{*customer})
}
2 changes: 1 addition & 1 deletion cli/print/customers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

var customersTmplSrc = `ID NAME CHANNELS EXPIRES TYPE
{{ range . -}}
{{ .ID }} {{ .Name }} {{range .Channels}}{{.Name}}{{end}} {{if not .Expires}}Never{{else}}{{.Expires}}{{end}} {{.Type}}
{{ .ID }} {{ .Name }} {{range .Channels}} {{.Name}}{{end}} {{if not .Expires}}Never{{else}}{{.Expires}}{{end}} {{.Type}}
{{ end }}`

var customersTmpl = template.Must(template.New("channels").Parse(customersTmplSrc))
Expand Down
8 changes: 4 additions & 4 deletions client/customer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ func (c *Client) ListCustomers(appID string, appType string) ([]types.Customer,
} else if appType == "ship" {
return nil, errors.New("listing customers is not supported for ship applications")
} else if appType == "kots" {
return c.KotsClient.ListCustomers(appID)
return c.KotsHTTPClient.ListCustomers(appID)
}

return nil, errors.Errorf("unknown app type %q", appType)
}

func (c *Client) CreateCustomer(appType string, name string, channelID string, expiresIn time.Duration) (*types.Customer, error) {
func (c *Client) CreateCustomer(appID, appType string, name string, channelID string, expiresIn time.Duration) (*types.Customer, error) {
if appType == "platform" {
return nil, errors.New("creating customers is not supported for platform applications")
} else if appType == "ship" {
return nil, errors.New("creating customers is not supported for ship applications")
} else if appType == "kots" {
return c.KotsClient.CreateCustomer(name, channelID, expiresIn)
return c.KotsHTTPClient.CreateCustomer(name, appID, channelID, expiresIn)
}

return nil, errors.Errorf("unknown app type %q", appType)
Expand All @@ -39,7 +39,7 @@ func (c *Client) GetCustomerByName(appType string, appID, name string) (*types.C
} else if appType == "ship" {
return nil, errors.New("listing customers is not supported for ship applications")
} else if appType == "kots" {
return c.KotsClient.GetCustomerByName(appID, name)
return c.KotsHTTPClient.GetCustomerByName(appID, name)
}

return nil, errors.Errorf("unknown app type %q", appType)
Expand Down
62 changes: 21 additions & 41 deletions pkg/kotsclient/customer_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,39 @@ package kotsclient

import (
"github.com/pkg/errors"
"github.com/replicatedhq/replicated/pkg/graphql"
"github.com/replicatedhq/replicated/pkg/types"
"net/http"
"time"
)

const kotsCreateCustomer = `
mutation createKotsCustomer($name: String!, $channelId: String!, $expiresAt: String) {
createKotsCustomer(name: $name, channelId: $channelId, isKots: true, airgap: false, type: "dev", entitlements: [], expiresAt: $expiresAt, isGitopsSupported: false) {
id
name
type
expiresAt
# cant fetch channels here
}
}`

type GraphQLResponseCreateCustomer struct {
Data *CreateCustomerData `json:"data,omitempty"`
Errors []graphql.GQLError `json:"errors,omitempty"`
type CreateCustomerRequest struct {
Name string `json:"name"`
ChannelID string `json:"channel_id"`
AppID string `json:"app_id"`
Type string `json:"type"`
ExpiresAt string `json:"expires_at"`
}

type CreateCustomerData struct {
Customer *Customer `json:"createKotsCustomer"`
type CreateCustomerResponse struct {
Customer *types.Customer `json:"customer"`
}

func (c *GraphQLClient) CreateCustomer(name, channel string, expiresIn time.Duration) (*types.Customer, error) {

response := GraphQLResponseCreateCustomer{}

request := graphql.Request{
Query: kotsCreateCustomer,
Variables: map[string]interface{}{
"name": name,
"channelId": channel,
},
}
if expiresIn > 0 {
request.Variables["expiresAt"] = (time.Now().Add(expiresIn)).Format(time.RFC3339)
func (c *HTTPClient) CreateCustomer(name string, appID string, channelID string, expiresIn time.Duration) (*types.Customer, error) {
request := &CreateCustomerRequest{
Name: name,
ChannelID: channelID,
AppID: appID,
Type: "dev", // hardcode for now
}

if err := c.ExecuteRequest(request, &response); err != nil {
return nil, errors.Wrap(err, "execute gql request")
if expiresIn > 0 {
request.ExpiresAt = (time.Now().UTC().Add(expiresIn)).Format(time.RFC3339)
}

customer, err := types.Customer{
ID: response.Data.Customer.ID,
Name: response.Data.Customer.Name,
Type: response.Data.Customer.Type,
}.WithExpiryTime(response.Data.Customer.ExpiresAt)

var response CreateCustomerResponse
err := c.DoJSON("POST", "/v3/customer", http.StatusCreated, request, &response)
if err != nil {
return nil, errors.Wrap(err, "set expiry time")
return nil, errors.Wrap(err, "create customer")
}

return &customer, nil
return response.Customer, nil
}
2 changes: 1 addition & 1 deletion pkg/kotsclient/customer_license_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"
)

func (c HTTPClient) DownloadLicense(appID string, customerID string) ([]byte, error) {
func (c *HTTPClient) DownloadLicense(appID string, customerID string) ([]byte, error) {
path := fmt.Sprintf("/v3/app/%s/customer/%s/license-download", appID, customerID)
licenseBytes, err := c.HTTPGet(path, http.StatusOK)
if err != nil {
Expand Down
94 changes: 13 additions & 81 deletions pkg/kotsclient/customer_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,103 +3,35 @@ package kotsclient
import (
"fmt"
"github.com/pkg/errors"
"github.com/replicatedhq/replicated/pkg/graphql"
"github.com/replicatedhq/replicated/pkg/types"
"net/http"
)

const kotsListCustomers = `
query customers($appId: String!, $appType: String!) {
customers(appId: $appId, appType: $appType) {
customers {
id
name
channels {
id
name
currentVersion
}
}
}
}
`

type GraphQLResponseListCustomers struct {
Data *CustomerDataWrapper `json:"data,omitempty"`
Errors []graphql.GQLError `json:"errors,omitempty"`
}

type CustomerDataWrapper struct {
Customers CustomerData `json:"customers"`
}

type CustomerData struct {
Customers []*Customer `json:"customers"`
}

type Customer struct {
ID string `json:"id"`
Name string `json:"name"`
Channels []*KotsChannel `json:"channels"`
Type string `json:"type"`
ExpiresAt string `json:"expiresAt"`
}

var _ error = ErrCustomerNotFound{}
type ErrCustomerNotFound struct {
Name string
}
func (e ErrCustomerNotFound) Error() string {
return fmt.Sprintf("customer %q not found", e.Name)
}

type CustomerListResponse struct {
Customers []types.Customer `json:"customers"`
}

func (c *HTTPClient) ListCustomers(appID string) ([]types.Customer, error) {

func (c *GraphQLClient) ListCustomers(appID string) ([]types.Customer, error) {
response := GraphQLResponseListCustomers{}

request := graphql.Request{
Query: kotsListCustomers,

Variables: map[string]interface{}{
"appId": appID,
"appType": "kots",
},
}

if err := c.ExecuteRequest(request, &response); err != nil {
return nil, errors.Wrap(err, "execute gql request")
}

customers := make([]types.Customer, 0, 0)
for _, kotsCustomer := range response.Data.Customers.Customers {

kotsChannels := make([]types.Channel, 0, 0)
for _, kotsChannel := range kotsCustomer.Channels {
channel := types.Channel{
ID: kotsChannel.ID,
Name: kotsChannel.Name,
ReleaseLabel: kotsChannel.CurrentVersion,
ReleaseSequence: kotsChannel.ReleaseSequence,
}
kotsChannels = append(kotsChannels, channel)
}
customer, err := types.Customer{
ID: kotsCustomer.ID,
Name: kotsCustomer.Name,
Type: kotsCustomer.Type,
Channels: kotsChannels,
}.WithExpiryTime(kotsCustomer.ExpiresAt)

if err != nil {
return nil, errors.Wrapf(err, "set expiry time for customer %q", kotsCustomer.ID)
}

customers = append(customers, customer)
path := fmt.Sprintf("/v3/app/%s/customers", appID)
var resp CustomerListResponse
err := c.DoJSON("GET", path, http.StatusOK, nil, &resp)
if err != nil {
return nil, errors.Wrapf(err, "list customers")
}
return resp.Customers, nil

return customers, nil
}

func (c *GraphQLClient) GetCustomerByName(appID string, name string) (*types.Customer, error) {
func (c *HTTPClient) GetCustomerByName(appID string, name string) (*types.Customer, error) {
allCustomers, err := c.ListCustomers(appID)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions pkg/platformclient/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// ListApps returns all apps and their channels.
func (c *HTTPClient) ListApps() ([]apps.AppAndChannels, error) {
appsAndChannels := make([]apps.AppAndChannels, 0)
err := c.doJSON("GET", "/v1/apps", http.StatusOK, nil, &appsAndChannels)
err := c.DoJSON("GET", "/v1/apps", http.StatusOK, nil, &appsAndChannels)
if err != nil {
return nil, err
}
Expand All @@ -36,7 +36,7 @@ func (c *HTTPClient) GetApp(slugOrID string) (*apps.App, error) {
func (c *HTTPClient) CreateApp(opts *AppOptions) (*apps.App, error) {
reqBody := &apps.Body{Name: opts.Name}
app := &apps.App{}
err := c.doJSON("POST", "/v1/app", http.StatusCreated, reqBody, app)
err := c.DoJSON("POST", "/v1/app", http.StatusCreated, reqBody, app)
if err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/platformclient/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (acs AppChannels) Less(i, j int) bool {
func (c *HTTPClient) ListChannels(appID string) ([]channels.AppChannel, error) {
path := fmt.Sprintf("/v1/app/%s/channels", appID)
appChannels := make([]channels.AppChannel, 0)
err := c.doJSON("GET", path, http.StatusOK, nil, &appChannels)
err := c.DoJSON("GET", path, http.StatusOK, nil, &appChannels)
if err != nil {
return nil, fmt.Errorf("ListChannels: %v", err)
}
Expand All @@ -46,7 +46,7 @@ func (c *HTTPClient) CreateChannel(appID string, name string, description string
Description: description,
}
appChannels := make([]channels.AppChannel, 0)
err := c.doJSON("POST", path, http.StatusOK, body, &appChannels)
err := c.DoJSON("POST", path, http.StatusOK, body, &appChannels)
if err != nil {
return fmt.Errorf("CreateChannel: %v", err)
}
Expand Down Expand Up @@ -94,7 +94,7 @@ func (crs ChannelReleases) Less(i, j int) bool {
func (c *HTTPClient) GetChannel(appID, channelID string) (*channels.AppChannel, []channels.ChannelRelease, error) {
path := fmt.Sprintf("/v1/app/%s/channel/%s/releases", appID, channelID)
respBody := channels.GetChannelInlineResponse200{}
err := c.doJSON("GET", path, http.StatusOK, nil, &respBody)
err := c.DoJSON("GET", path, http.StatusOK, nil, &respBody)
if err != nil {
return nil, nil, fmt.Errorf("GetChannel: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/platformclient/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func (c *HTTPClient) PromoteCollector(appID string, specID string, channelIDs ..
body := &v1.BodyPromoteCollector{
ChannelIDs: channelIDs,
}
if err := c.doJSON("POST", path, http.StatusOK, body, nil); err != nil {
if err := c.DoJSON("POST", path, http.StatusOK, body, nil); err != nil {
return fmt.Errorf("PromoteCollector: %v", err)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/platformclient/license.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// CreateLicense creates a new License.
func (c *HTTPClient) CreateLicense(license *v2.LicenseV2) (*v2.LicenseV2, error) {
created := &v2.LicenseV2{}
if err := c.doJSON("POST", "/v2/license", http.StatusCreated, license, created); err != nil {
if err := c.DoJSON("POST", "/v2/license", http.StatusCreated, license, created); err != nil {
return nil, fmt.Errorf("CreateLicense: %v", err)
}
return created, nil
Expand Down
8 changes: 4 additions & 4 deletions pkg/platformclient/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func (c *HTTPClient) ListReleases(appID string) ([]releases.AppReleaseInfo, error) {
path := fmt.Sprintf("/v1/app/%s/releases", appID)
releases := make([]releases.AppReleaseInfo, 0)
if err := c.doJSON("GET", path, http.StatusOK, nil, &releases); err != nil {
if err := c.DoJSON("GET", path, http.StatusOK, nil, &releases); err != nil {
return nil, fmt.Errorf("ListReleases: %v", err)
}
return releases, nil
Expand All @@ -27,7 +27,7 @@ func (c *HTTPClient) CreateRelease(appID string, yaml string) (*releases.AppRele
Source: "latest",
}
release := &releases.AppReleaseInfo{}
if err := c.doJSON("POST", path, http.StatusCreated, body, release); err != nil {
if err := c.DoJSON("POST", path, http.StatusCreated, body, release); err != nil {
return nil, fmt.Errorf("CreateRelease: %v", err)
}
// API does not accept yaml in create operation, so first create then udpate
Expand Down Expand Up @@ -66,7 +66,7 @@ func (c *HTTPClient) UpdateRelease(appID string, sequence int64, yaml string) er
func (c *HTTPClient) GetRelease(appID string, sequence int64) (*releases.AppRelease, error) {
path := fmt.Sprintf("/v1/app/%s/%d/properties", appID, sequence)
release := &releases.AppRelease{}
if err := c.doJSON("GET", path, http.StatusOK, nil, release); err != nil {
if err := c.DoJSON("GET", path, http.StatusOK, nil, release); err != nil {
return nil, fmt.Errorf("GetRelease: %v", err)
}
return release, nil
Expand All @@ -81,7 +81,7 @@ func (c *HTTPClient) PromoteRelease(appID string, sequence int64, label, notes s
Required: required,
Channels: channelIDs,
}
if err := c.doJSON("POST", path, http.StatusNoContent, body, nil); err != nil {
if err := c.DoJSON("POST", path, http.StatusNoContent, body, nil); err != nil {
return fmt.Errorf("PromoteRelease: %v", err)
}
return nil
Expand Down
Loading