Skip to content

Commit

Permalink
GED project Admiral API (#177)
Browse files Browse the repository at this point in the history
* Add support for gtp with multiple traffic policies (#162)

Fixes #163
Fixes #161

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* Fix mesh port match against to look at k8s svc target port (#165)

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* Add basic health check API  (#171)

* some basic folder

* get the basic curl /health/ready working

* Refactoring api server files

* reverting a very tiny comment that I shouldn't have pushed

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* trying to fix the circle CI error

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* addressed the comment

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

Co-authored-by: vjoshi3 <vrushali_joshi@intuit.com>
Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* Admiral apis (#175)

* added the get all cluste api

Signed-off-by: Mengying <mengyinglimandy@gmail.com>
Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* fixed the unit test

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* updated the comment a little bit

Signed-off-by: Mengying <mengyinglimandy@gmail.com>
Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* Adding api to get service entries based on given cluster or given identity

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* Refactoring api code

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* Fixing failing tests for service.go

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* Fixing review comments and ci failures

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* Fixing review comments

Signed-off-by: vjoshi3 <vrushali_joshi@intuit.com>

* added some unit tests

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* added the cluster id inside deployment controller (#176)

* added the cluster id inside deployment controller

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* fixed the helm setup failure

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* added cluster id in other remote controllers

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* added unit test for api function GetServiceEntriesByCluster

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* fixed a small typing in test

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* fixed some indentation

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* added test for get se by identity

Signed-off-by: Mengying <mengyinglimandy@gmail.com>

* added cluster id to be print in log

Co-authored-by: Mengying <mengyinglimandy@gmail.com>
Co-authored-by: vjoshi3 <vrushali_joshi@intuit.com>
Co-authored-by: Mengying-Li <43981707+Mengying-Li@users.noreply.github.com>

* added more context to the API call

Co-authored-by: aattuluri <44482891+aattuluri@users.noreply.github.com>
Co-authored-by: vjoshi3 <vrushali_joshi@intuit.com>
Co-authored-by: vrushalijoshi <vrushalijoshi.cummins@gmail.com>
  • Loading branch information
4 people authored May 24, 2021
1 parent 44964f2 commit bbe53a0
Show file tree
Hide file tree
Showing 20 changed files with 834 additions and 244 deletions.
24 changes: 21 additions & 3 deletions admiral/cmd/admiral/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"flag"
"fmt"
"github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/routes"
"github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/server"
"github.com/istio-ecosystem/admiral/admiral/pkg/clusters"
"github.com/istio-ecosystem/admiral/admiral/pkg/controller/common"
log "github.com/sirupsen/logrus"
Expand All @@ -25,6 +27,8 @@ func GetRootCmd(args []string) *cobra.Command {

params := common.AdmiralParams{LabelSet: &common.LabelSet{}}

opts := routes.RouteOpts{}

rootCmd := &cobra.Command{
Use: "Admiral",
Short: "Admiral is a control plane of control planes",
Expand All @@ -39,12 +43,26 @@ func GetRootCmd(args []string) *cobra.Command {
Run: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.Level(params.LogLevel))
log.Info("Starting Admiral")
_, err := clusters.InitAdmiral(ctx, params)
remoteRegistry, err := clusters.InitAdmiral(ctx, params)

if err != nil {
log.Fatalf("Error: %v", err)
}

service := server.Service{}
opts.RemoteRegistry = remoteRegistry
ret_routes := routes.NewAdmiralAPIServer(&opts)

if err != nil {
log.Error("Error setting up server:", err.Error())
}

service.Start(ctx, 8080, ret_routes, routes.Filter, remoteRegistry)

log.WithFields(log.Fields{
"error": err.Error(),
}).Fatal("Error setting up the server")

},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
shutdown(cancel)
Expand Down Expand Up @@ -94,8 +112,8 @@ func GetRootCmd(args []string) *cobra.Command {
rootCmd.PersistentFlags().StringVar(&params.WorkloadSidecarName, "workload_sidecar_name", "default",
"Name of the sidecar resource in the workload namespace. By default sidecar resource will be named as \"default\".")
rootCmd.PersistentFlags().StringVar(&params.LabelSet.EnvKey, "env_key", "admiral.io/env",
"The annotation or label, on a pod spec in a deployment, which will be used to group deployments across regions/clusters under a single environment. Defaults to `admiral.io/env`. " +
"The order would be to use annotation specified as `env_key`, followed by label specified as `env_key` and then fallback to the label `env`")
"The annotation or label, on a pod spec in a deployment, which will be used to group deployments across regions/clusters under a single environment. Defaults to `admiral.io/env`. "+
"The order would be to use annotation specified as `env_key`, followed by label specified as `env_key` and then fallback to the label `env`")

return rootCmd
}
Expand Down
43 changes: 43 additions & 0 deletions admiral/pkg/apis/admiral/filters/filters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package filters

import (
"io/ioutil"
"log"
"net/http"
"time"
)

/*
* func for the "middleware" or filters for example Access logging or processing Authn/z
*/

func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

inner.ServeHTTP(w, r)
body, _ := ioutil.ReadAll(r.Body)

log.Printf(
"Access Logger %s\t%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
name,
time.Since(start),
string(body),
)
})
}

func Auth(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

log.Printf(
"Auth Logger for endpoint %s", name,
)
//TODO implement authnz

inner.ServeHTTP(w, r)

})
}
214 changes: 214 additions & 0 deletions admiral/pkg/apis/admiral/routes/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package routes

import (
"bytes"
"encoding/json"
"github.com/gorilla/mux"
"github.com/istio-ecosystem/admiral/admiral/pkg/clusters"
"github.com/istio-ecosystem/admiral/admiral/pkg/controller/common"
"github.com/istio-ecosystem/admiral/admiral/pkg/controller/istio"
"github.com/istio-ecosystem/admiral/admiral/pkg/controller/secret"
"github.com/stretchr/testify/assert"
"io/ioutil"
"istio.io/client-go/pkg/apis/networking/v1alpha3"
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
"net/http/httptest"
"strings"
"testing"
)

func TestReturnSuccessGET (t *testing.T) {
url := "https://admiral.com/health"
opts := RouteOpts{}
r := httptest.NewRequest("GET", url, strings.NewReader(""))
w := httptest.NewRecorder()

opts.ReturnSuccessGET(w, r)
resp := w.Result()
assert.Equal(t, 200, resp.StatusCode)
}

func TestGetClusters (t *testing.T) {
url := "https://admiral.com/clusters"
opts := RouteOpts{
RemoteRegistry: &clusters.RemoteRegistry{
SecretController: &secret.Controller{
Cs: &secret.ClusterStore{
RemoteClusters: map[string]*secret.RemoteCluster{},
},
},
},
}
testCases := []struct {
name string
remoteCluster map[string]*secret.RemoteCluster
expectedErr interface{}
statusCode int
}{
{
name: "success with two clusters case",
remoteCluster: map[string]*secret.RemoteCluster{
"cluster1": &secret.RemoteCluster{},
"cluster2": &secret.RemoteCluster{},
},
expectedErr: []string{"cluster1", "cluster2"},
statusCode: 200,
},
{
name: "success with no cluster case",
remoteCluster: map[string]*secret.RemoteCluster{},
expectedErr: "No cluster is monitored by admiral",
statusCode: 200,
},
}
//Run the test for every provided case
for _, c := range testCases {
t.Run(c.name, func(t *testing.T) {
r:= httptest.NewRequest("GET", url, strings.NewReader(""))
w := httptest.NewRecorder()
opts.RemoteRegistry.SecretController.Cs.RemoteClusters = c.remoteCluster
opts.GetClusters(w, r)
resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)
expectedOutput, _ := json.Marshal(c.expectedErr)
if bytes.Compare(body, expectedOutput) != 0 {
t.Errorf("Error mismatch. Got %v, want %v", string(body), c.expectedErr)
t.Errorf("%d",bytes.Compare(body, expectedOutput))
}
if c.statusCode != 200 && resp.StatusCode != c.statusCode {
t.Errorf("Status code mismatch. Got %v, want %v", resp.StatusCode, c.statusCode)
}
})
}
}

func TestGetServiceEntriesByCluster (t *testing.T) {
url := "https://admiral.com/cluster/cluster1/serviceentries"
opts := RouteOpts{
RemoteRegistry: &clusters.RemoteRegistry{},
}
fakeIstioClient := istiofake.NewSimpleClientset()
testCases := []struct {
name string
clusterName string
remoteControllers map[string]*clusters.RemoteController
expectedErr string
statusCode int
}{
{
name: "failure with admiral not monitored cluster",
clusterName: "bar",
remoteControllers: nil,
expectedErr: "Admiral is not monitoring cluster bar\n",
statusCode: 404,
},
{
name: "failure with cluster not provided request",
clusterName: "",
remoteControllers: nil,
expectedErr: "Cluster name not provided as part of the request\n",
statusCode: 400,
},
{
name: "success with no service entry for cluster",
clusterName: "cluster1",
remoteControllers:map[string]*clusters.RemoteController{
"cluster1": &clusters.RemoteController{
ServiceEntryController: &istio.ServiceEntryController{
IstioClient: fakeIstioClient,
},
},
},
expectedErr: "No service entries configured for cluster - cluster1",
statusCode: 200,
},
{
name: "success with service entry for cluster",
clusterName: "cluster1",
remoteControllers: map[string]*clusters.RemoteController{
"cluster1": &clusters.RemoteController{
ServiceEntryController: &istio.ServiceEntryController{
IstioClient: fakeIstioClient,
},
},
},
expectedErr: "",
statusCode: 200,
},
}
//Run the test for every provided case
for _, c := range testCases {
t.Run(c.name, func(t *testing.T) {
r:= httptest.NewRequest("GET", url, nil)
r = mux.SetURLVars(r, map[string]string{"clustername": c.clusterName})
w := httptest.NewRecorder()
opts.RemoteRegistry.RemoteControllers = c.remoteControllers
if c.name == "success with service entry for cluster" {
fakeIstioClient.NetworkingV1alpha3().ServiceEntries("admiral-sync").Create(&v1alpha3.ServiceEntry{})
}
opts.GetServiceEntriesByCluster(w, r)
resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)
if string(body) != c.expectedErr && c.name != "success with service entry for cluster" {
t.Errorf("Error mismatch. Got %v, want %v", string(body), c.expectedErr)
}
if resp.StatusCode != c.statusCode {
t.Errorf("Status code mismatch. Got %v, want %v", resp.StatusCode, c.statusCode)
}
})
}
}

func TestGetServiceEntriesByIdentity (t *testing.T) {
url := "https://admiral.com/identity/service1/serviceentries"
opts := RouteOpts{
RemoteRegistry: &clusters.RemoteRegistry{
AdmiralCache: &clusters.AdmiralCache{
SeClusterCache: common.NewMapOfMaps() ,
},
},
}
testCases := []struct {
name string
identity string
host string
expectedErr string
statusCode int
}{
{
name: "failure with identity not provided request",
identity: "",
host: "",
expectedErr: "Identity not provided as part of the request\n",
statusCode: 400,
},
{
name: "success with service entry for service",
identity: "meshhealthcheck",
host: "anil-test-bdds-10-k8s-e2e.intuit.services.mesh.meshhealthcheck.mesh",
expectedErr: "Identity not provided as part of the request\n",
statusCode: 200,
},
}
//Run the test for every provided case
for _, c := range testCases {
t.Run(c.name, func(t *testing.T) {
r:= httptest.NewRequest("GET", url, nil)
r = mux.SetURLVars(r, map[string]string{"identity": c.identity})
w := httptest.NewRecorder()
if c.host != "" {
opts.RemoteRegistry.AdmiralCache.SeClusterCache.Put(c.host, "cluster1", "cluster1")
}
opts.GetServiceEntriesByIdentity(w, r)
resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)
if string(body) != c.expectedErr && c.name != "success with service entry for service" {
t.Errorf("Error mismatch. Got %v, want %v", string(body), c.expectedErr)
}
if resp.StatusCode != c.statusCode {
t.Errorf("Status code mismatch. Got %v, want %v", resp.StatusCode, c.statusCode)
}
})
}
}

Loading

0 comments on commit bbe53a0

Please sign in to comment.