Skip to content

Commit

Permalink
Add stack endpoints (#1866)
Browse files Browse the repository at this point in the history
* Add stack endpoints

Signed-off-by: Javier López Barba <javier@okteto.com>

* Fix infinite loop

Signed-off-by: Javier López Barba <javier@okteto.com>

* Fix spinner displayed before endpoint list

Signed-off-by: Javier López Barba <javier@okteto.com>

* Fix stacks endpoints order

Signed-off-by: Javier López Barba <javier@okteto.com>

* Refactor available endpoints message

Signed-off-by: Javier López Barba <javier@okteto.com>
  • Loading branch information
jLopezbarb committed Nov 10, 2021
1 parent a017290 commit e06fd24
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 0 deletions.
7 changes: 7 additions & 0 deletions cmd/stack/deploy.go
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/okteto/okteto/pkg/cmd/stack"
"github.com/okteto/okteto/pkg/log"
"github.com/okteto/okteto/pkg/model"
"github.com/okteto/okteto/pkg/okteto"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -64,6 +65,12 @@ func Deploy(ctx context.Context) *cobra.Command {
if err == nil {
log.Success("Stack '%s' successfully deployed", s.Name)
}
if okteto.Context().IsOkteto {
if err := stack.ListEndpoints(ctx, s, ""); err != nil {
return err
}
}

return err
},
}
Expand Down
72 changes: 72 additions & 0 deletions cmd/stack/endpoints.go
@@ -0,0 +1,72 @@
// Copyright 2021 The Okteto Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package stack

import (
"context"
"fmt"

contextCMD "github.com/okteto/okteto/cmd/context"
"github.com/okteto/okteto/pkg/cmd/stack"
"github.com/okteto/okteto/pkg/errors"
"github.com/okteto/okteto/pkg/log"
"github.com/okteto/okteto/pkg/okteto"
"github.com/spf13/cobra"
)

// Endpoints show all the endpoints of a stack
func Endpoints(ctx context.Context) *cobra.Command {
var (
output string
name string
namespace string
stackPath []string
)
cmd := &cobra.Command{
Use: "endpoints [service...]",
Short: "Show endpoints for a stack",
RunE: func(cmd *cobra.Command, args []string) error {

s, err := contextCMD.LoadStackWithContext(ctx, name, namespace, stackPath)
if err != nil {
return err
}
if !okteto.IsOkteto() {
return errors.ErrContextIsNotOktetoCluster
}

if err := validateOutput(output); err != nil {
return err
}

if err := stack.ListEndpoints(ctx, s, output); err != nil {
log.Success("Stack '%s' successfully deployed", s.Name)
}
return nil
},
}
cmd.Flags().StringVarP(&output, "output", "o", "", "output format. One of: ['json']")
cmd.Flags().StringArrayVarP(&stackPath, "file", "f", []string{}, "path to the stack manifest files. If more than one is passed the latest will overwrite the fields from the previous")
cmd.Flags().StringVarP(&name, "name", "", "", "overwrites the stack name")
cmd.Flags().StringVarP(&namespace, "namespace", "n", "", "overwrites the stack namespace where the stack is deployed")

return cmd
}

func validateOutput(output string) error {
if output != "" && output != "json" {
return fmt.Errorf("output format is not accepted. Value must be one of: ['json']")
}
return nil
}
1 change: 1 addition & 0 deletions cmd/stack/stack.go
Expand Up @@ -29,5 +29,6 @@ func Stack(ctx context.Context) *cobra.Command {
}
cmd.AddCommand(Deploy(ctx))
cmd.AddCommand(Destroy(ctx))
cmd.AddCommand(Endpoints(ctx))
return cmd
}
60 changes: 60 additions & 0 deletions pkg/cmd/stack/endpoints.go
@@ -0,0 +1,60 @@
// Copyright 2021 The Okteto Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package stack

import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"

"github.com/okteto/okteto/pkg/log"
"github.com/okteto/okteto/pkg/model"
"github.com/okteto/okteto/pkg/okteto"
)

func ListEndpoints(ctx context.Context, stack *model.Stack, output string) error {
oktetoClient, err := okteto.NewOktetoClient()
if err != nil {
return err
}
endpointList, err := oktetoClient.ListStackEndpoints(ctx, stack)
if err != nil {
return fmt.Errorf("failed to get preview environments: %s", err)
}

switch output {
case "json":
bytes, err := json.MarshalIndent(endpointList, "", " ")
if err != nil {
return err
}
fmt.Println(string(bytes))
default:
if len(endpointList) == 0 {
log.Information("There are no available endpoints for stack '%s'\n", stack.Name)
} else {
endpoints := make([]string, 0)
for _, endpoint := range endpointList {
endpoints = append(endpoints, endpoint.URL)
}
sort.Slice(endpoints, func(i, j int) bool {
return len(endpoints[i]) < len(endpoints[j])
})
log.Information("Endpoints available:\n - %s\n", strings.Join(endpoints, "\n - "))
}
}
return nil
}
88 changes: 88 additions & 0 deletions pkg/okteto/stack.go
@@ -0,0 +1,88 @@
// Copyright 2020 The Okteto Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package okteto

import (
"context"
"fmt"

"github.com/okteto/okteto/pkg/model"
"github.com/shurcooL/graphql"
)

func (c *OktetoClient) ListStackEndpoints(ctx context.Context, stack *model.Stack) ([]Endpoint, error) {
var query struct {
Space struct {
Stacks []struct {
Id graphql.String
Name graphql.String
}
Deployments []struct {
DeployedBy graphql.String
Endpoints []struct {
Url graphql.String
}
}
Statefulsets []struct {
DeployedBy graphql.String
Endpoints []struct {
Url graphql.String
}
}
} `graphql:"space(id: $id)"`
}

variables := map[string]interface{}{
"id": graphql.String(stack.Namespace),
}
endpoints := make([]Endpoint, 0)

err := c.client.Query(ctx, &query, variables)
if err != nil {
return nil, translateAPIErr(err)
}

var stackId string
for _, queriedStack := range query.Space.Stacks {
if stack.Name == string(queriedStack.Name) {
stackId = string(queriedStack.Id)
}
}
if stackId == "" {
return nil, fmt.Errorf("stack '%s' not found", stack.Name)
}

for _, d := range query.Space.Deployments {
if string(d.DeployedBy) != stackId {
continue
}
for _, endpoint := range d.Endpoints {
endpoints = append(endpoints, Endpoint{
URL: string(endpoint.Url),
})
}
}

for _, sfs := range query.Space.Statefulsets {
if string(sfs.DeployedBy) != stackId {
continue
}
for _, endpoint := range sfs.Endpoints {
endpoints = append(endpoints, Endpoint{
URL: string(endpoint.Url),
})
}
}
return endpoints, nil
}

0 comments on commit e06fd24

Please sign in to comment.