Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-Context Support #4218

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ee22b9b
add k8scontext persister
tangledbytes Sep 6, 2021
f90d300
add new k8scontext construct
tangledbytes Sep 6, 2021
8248fa0
add complete implementation of contexts interface in local provider a…
tangledbytes Sep 6, 2021
41b0488
add contexts handlers to the interface
tangledbytes Sep 6, 2021
b11786d
remove older k8s constructs
tangledbytes Sep 6, 2021
ef661a4
replace legacy k8sconfig reader with new implementation and setup dat…
tangledbytes Sep 6, 2021
04bd863
accomodate for changes in k8s constructs
tangledbytes Sep 6, 2021
0ca9079
move pattern utils to helpers
tangledbytes Sep 20, 2021
7c84875
add context CRUD routes
tangledbytes Sep 20, 2021
14a71b6
change kubeconfig generation strategy
tangledbytes Sep 20, 2021
ad0de35
add complete support for remote providers
tangledbytes Sep 20, 2021
898abfa
partially incorporate API changes in the UI
tangledbytes Sep 20, 2021
64b8e1a
incorporate contexts related changes in the middleware flow
tangledbytes Sep 20, 2021
2e41e0a
add package-lock.json
tangledbytes Sep 20, 2021
6037595
merge upstream master
tangledbytes Sep 20, 2021
aae6174
merge upstream master
tangledbytes Sep 20, 2021
3adf682
remove unnecessary logging
tangledbytes Sep 20, 2021
627f9a7
Merge branch 'master' into utkarsh-pro/feature/multi-context-support
leecalcote Sep 20, 2021
76340fb
add ping test to the contexts
tangledbytes Sep 23, 2021
29db1ce
add support for kubernete server ID extraction and placement in the c…
tangledbytes Sep 23, 2021
7e6761d
Merge branch 'master' into utkarsh-pro/feature/multi-context-support
leecalcote Sep 24, 2021
4129dfa
Merge remote-tracking branch 'upstream/master' into utkarsh-pro/featu…
tangledbytes Sep 27, 2021
28f67fc
fix support for in cluster deployemnts
tangledbytes Sep 27, 2021
278da16
fix success message banner style
tangledbytes Sep 27, 2021
3ae082a
use meshkit errors and add logging - additional cleanups tpp
tangledbytes Sep 27, 2021
fbbb131
Merge remote-tracking branch 'origin/utkarsh-pro/feature/multi-contex…
tangledbytes Sep 27, 2021
bbac986
fix golangci lint errors
tangledbytes Sep 27, 2021
89df4c5
merge upstream master
tangledbytes Nov 15, 2021
8be8d38
update package-lock.json
tangledbytes Nov 15, 2021
4305282
Squash commit
tangledbytes Nov 17, 2021
6e81f3e
Squash commit
tangledbytes Nov 24, 2021
6065dc3
extract k8s contexts from the query parameters and inject into contexts
tangledbytes Dec 3, 2021
e00599a
add support for multi contexts request for handlers
tangledbytes Dec 3, 2021
810d167
fix "all" contexts bug'
tangledbytes Dec 9, 2021
9add674
merge upstream master
tangledbytes Dec 13, 2021
b63fb23
Merge branch 'master' into utkarsh-pro/feature/multi-context-support
leecalcote Jan 4, 2022
5c293ec
Add imports
Revolyssup Feb 11, 2022
0c4bc75
Merge upstream master
tangledbytes Feb 11, 2022
5562df7
finalize UI
tangledbytes Feb 13, 2022
2e0e207
merge origin branch
tangledbytes Feb 13, 2022
e0fdc8d
merge upstream master
tangledbytes Feb 13, 2022
9ab1e2d
remove lint issue
Revolyssup Feb 13, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 16 additions & 9 deletions cmd/main.go
Expand Up @@ -10,10 +10,10 @@ import (
"path"
"time"

"github.com/gofrs/uuid"
"github.com/layer5io/meshery/handlers"
"github.com/layer5io/meshery/helpers"
"github.com/layer5io/meshery/internal/graphql"
"github.com/layer5io/meshery/internal/graphql/model"
"github.com/layer5io/meshery/internal/store"
"github.com/layer5io/meshery/models"
"github.com/layer5io/meshery/models/pattern/core"
Expand All @@ -22,7 +22,6 @@ import (
"github.com/layer5io/meshkit/database"
"github.com/layer5io/meshkit/logger"
"github.com/layer5io/meshkit/utils/broadcast"
mesherykube "github.com/layer5io/meshkit/utils/kubernetes"
meshsyncmodel "github.com/layer5io/meshsync/pkg/model"
"github.com/spf13/viper"

Expand All @@ -49,6 +48,12 @@ func main() {
models.GlobalTokenForAnonymousResults = globalTokenForAnonymousResults
}

instanceID, err := uuid.NewV4()
if err != nil {
logrus.Error(err)
os.Exit(1)
}

// Initialize Logger instance
log, err := logger.New("meshery", logger.Options{
Format: logger.SyslogLogFormat,
Expand All @@ -73,6 +78,8 @@ func main() {
viper.SetDefault("OS", "meshery")
viper.SetDefault("COMMITSHA", commitsha)
viper.SetDefault("RELEASE_CHANNEL", releasechannel)
viper.SetDefault("INSTANCE_ID", &instanceID)

viper.SetDefault("SKIP_DOWNLOAD_CONTENT", false)
viper.SetDefault("SKIP_COMP_GEN", false)
store.Initialize()
Expand Down Expand Up @@ -148,7 +155,6 @@ func main() {
logrus.Fatal(err)
}

kubeclient := mesherykube.Client{}
meshsyncCh := make(chan struct{})
brokerConn := nats.NewEmptyConnection

Expand All @@ -167,6 +173,7 @@ func main() {
&models.UserPreference{},
&models.PerformanceTestConfig{},
&models.SmiResultWithID{},
models.K8sContext{},
)
if err != nil {
logrus.Fatal(err)
Expand All @@ -183,6 +190,7 @@ func main() {
MesheryFilterPersister: &models.MesheryFilterPersister{DB: &dbHandler},
MesheryApplicationPersister: &models.MesheryApplicationPersister{DB: &dbHandler},
MesheryPatternResourcePersister: &models.PatternResourcePersister{DB: &dbHandler},
MesheryK8sContextPersister: &models.MesheryK8sContextPersister{DB: &dbHandler},
GenericPersister: dbHandler,
}
lProv.Initialize()
Expand Down Expand Up @@ -226,7 +234,6 @@ func main() {
Queue: mainQueue,

KubeConfigFolder: viper.GetString("KUBECONFIG_FOLDER"),
KubeClient: &kubeclient,

GrafanaClient: models.NewGrafanaClient(),
GrafanaClientForQuery: models.NewGrafanaClientWithHTTPClient(&http.Client{Timeout: time.Second}),
Expand Down Expand Up @@ -277,11 +284,11 @@ func main() {

// only uninstalls meshery-operator using helm charts
// useful for dev deployments
logrus.Info("Uninstalling meshery-operator...")
err = model.Initialize(&kubeclient, true, adapterTracker)
if err != nil {
log.Error(err)
}
// logrus.Info("Uninstalling meshery-operator...")
// err = model.Initialize(&kubeclient, true, adapterTracker)
// if err != nil {
// log.Error(err)
// }

logrus.Info("Shutting down Meshery")
}
20 changes: 7 additions & 13 deletions handlers/content_modifier.go
@@ -1,12 +1,12 @@
package handlers

import (
"context"
"encoding/json"
"sync"

"github.com/layer5io/meshery/models"
"github.com/layer5io/meshery/models/pattern/core"
meshkube "github.com/layer5io/meshkit/utils/kubernetes"
"gopkg.in/yaml.v2"
)

Expand All @@ -32,7 +32,7 @@ func NewContentModifier(token string,

//TODO: Similar mechanisms for filters and applications
//Takes in response bytes, and add metadata to it based on some checks
func (mc *ContentModifier) AddMetadataForPatterns(contentBytes *[]byte) error {
func (mc *ContentModifier) AddMetadataForPatterns(ctx context.Context, contentBytes *[]byte) error {
var patternsPage models.MesheryPatternPage
err := json.Unmarshal(*contentBytes, &patternsPage)
if err != nil {
Expand Down Expand Up @@ -63,7 +63,7 @@ func (mc *ContentModifier) AddMetadataForPatterns(contentBytes *[]byte) error {
if err != nil {
return
}
msg, ok := mc.isPatternSupported(patterncontent)
msg, ok := mc.isPatternSupported(ctx, patterncontent)
(*p)[i]["canSupport"] = ok
(*p)[i]["errmsg"] = msg
}(pattern, i, &p, mc.token, mc.provider, mc.prefObj, mc.userID)
Expand All @@ -78,7 +78,7 @@ func (mc *ContentModifier) AddMetadataForPatterns(contentBytes *[]byte) error {
}

//takes a patternfile and returns the status of its current support by using dry run
func (mc *ContentModifier) isPatternSupported(patternfile string) (msg string, ok bool) {
func (mc *ContentModifier) isPatternSupported(ctx context.Context, patternfile string) (msg string, ok bool) {
var pattern map[string]interface{}
err := yaml.Unmarshal([]byte(patternfile), &pattern)
if err != nil {
Expand All @@ -88,19 +88,12 @@ func (mc *ContentModifier) isPatternSupported(patternfile string) (msg string, o
if err != nil {
return err.Error(), false
}
if mc.prefObj == nil || mc.prefObj.K8SConfig == nil || mc.prefObj.K8SConfig.Config == nil {
return "could not detect kube config from preference", false
}
kc, err := meshkube.New(mc.prefObj.K8SConfig.Config) //possible nil dereference
if err != nil {
return err.Error(), false
}

msg, err = _processPattern(
mc.token,
ctx,
mc.provider,
patternFile,
mc.prefObj,
kc,
mc.userID,
false,
true,
Expand All @@ -109,5 +102,6 @@ func (mc *ContentModifier) isPatternSupported(patternfile string) (msg string, o
if err != nil {
return err.Error(), false
}

return msg, true
}
111 changes: 111 additions & 0 deletions handlers/contexts_handler.go
@@ -0,0 +1,111 @@
package handlers

import (
"encoding/json"
"net/http"

"github.com/gorilla/mux"
"github.com/layer5io/meshery/models"
)

func (h *Handler) GetAllContexts(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) {
token, ok := req.Context().Value(models.TokenCtxKey).(string)
if !ok {
http.Error(w, "failed to get token", http.StatusInternalServerError)
return
}

q := req.URL.Query()

vals, err := provider.GetK8sContexts(token, q.Get("page"), q.Get("pageSize"), q.Get("search"), q.Get("order"))
if err != nil {
http.Error(w, "failed to get contexts", http.StatusInternalServerError)
return
}

if err := json.NewEncoder(w).Encode(vals); err != nil {
http.Error(w, "failed to encode contexts", http.StatusInternalServerError)
return
}
}

func (h *Handler) GetContext(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) {
if req.URL.Query().Get("current") != "" {
context, ok := req.Context().Value(models.KubeContextKey).(*models.K8sContext)
if !ok || context == nil {
http.Error(w, "failed to get context", http.StatusInternalServerError)
return
}

if err := json.NewEncoder(w).Encode(context); err != nil {
http.Error(w, "failed to encode context", http.StatusInternalServerError)
return
}

return
}

token, ok := req.Context().Value(models.TokenCtxKey).(string)
if !ok {
http.Error(w, "failed to get token", http.StatusInternalServerError)
return
}

val, err := provider.GetK8sContext(token, mux.Vars(req)["id"])
if err != nil {
http.Error(w, "failed to get context", http.StatusInternalServerError)
return
}

if err := json.NewEncoder(w).Encode(val); err != nil {
http.Error(w, "failed to encode context", http.StatusInternalServerError)
return
}
}

func (h *Handler) DeleteContext(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) {
token, ok := req.Context().Value(models.TokenCtxKey).(string)
if !ok {
http.Error(w, "failed to get token", http.StatusInternalServerError)
return
}

_, err := provider.DeleteK8sContext(token, mux.Vars(req)["id"])
if err != nil {
http.Error(w, "failed to delete context", http.StatusInternalServerError)
return
}
}

func (h *Handler) GetCurrentContextHandler(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) {
token, ok := req.Context().Value(models.TokenCtxKey).(string)
if !ok {
http.Error(w, "failed to get token", http.StatusInternalServerError)
return
}

val, err := h.GetCurrentContext(token, provider)
if err != nil {
http.Error(w, "failed to get current context", http.StatusInternalServerError)
return
}

if err := json.NewEncoder(w).Encode(val); err != nil {
http.Error(w, "failed to encode context", http.StatusInternalServerError)
return
}
}

func (h *Handler) SetCurrentContextHandler(w http.ResponseWriter, req *http.Request, prefObj *models.Preference, user *models.User, provider models.Provider) {
token, ok := req.Context().Value(models.TokenCtxKey).(string)
if !ok {
http.Error(w, "failed to get token", http.StatusInternalServerError)
return
}

_, err := provider.SetCurrentContext(token, mux.Vars(req)["id"])
if err != nil {
http.Error(w, "failed to set current context", http.StatusInternalServerError)
return
}
}
4 changes: 2 additions & 2 deletions handlers/doc.go
Expand Up @@ -263,14 +263,14 @@ type adapterParamsWrapper struct {
// swagger:response k8sConfigRespWrapper
type k8sConfigRespWrapper struct {
// in: body
Body *models.K8SConfig
// Body *models.K8SConfig
}

// Returns kubernetes context list
// swagger:response k8sContextsRespWrapper
type k8sContextsRespWrapper struct {
// in: body
Body []*models.K8SContext
// Body []*models.K8SContext
}

// Parameters for updating provider choice
Expand Down
41 changes: 29 additions & 12 deletions handlers/error.go
Expand Up @@ -96,21 +96,26 @@ const (
ErrDecodePatternCode = "2169"
ErrParsePatternCode = "2170"
ErrConvertPatternCode = "2171"
ErrMesheryInstanceIDCode = "2173"
ErrInvalidKubeConfigCode = "2174"
ErrInvalidKubeHandlerCode = "2175"
ErrInvalidKubeContextCode = "2176"
)

var (
ErrInvalidK8SConfig = errors.New(ErrInvalidK8SConfigCode, errors.Alert, []string{"No valid kubernetes config found"}, []string{"Kubernetes config is not initialized with Meshery"}, []string{"Kubernetes config is not accessible to meshery or not valid"}, []string{"Upload your kubernetes config via the settings dashboard. If uploaded, wait for a minute for it to get initialized"})
ErrNilClient = errors.New(ErrNilClientCode, errors.Alert, []string{"Kubernetes client not initialized"}, []string{"Kubernetes config is not initialized with Meshery"}, []string{"Kubernetes config is not accessible to meshery or not valid"}, []string{"Upload your kubernetes config via the settings dashboard. If uploaded, wait for a minute for it to get initialized"})
ErrPrometheusConfig = errors.New(ErrPrometheusConfigCode, errors.Alert, []string{"Prometheus endpoint not configured"}, []string{"Cannot find valid Prometheus endpoint in user pref"}, []string{"Prometheus endpoint might not be reachable from meshery"}, []string{"Setup your Prometheus Endpoint via the settings dashboard"})
ErrGrafanaConfig = errors.New(ErrGrafanaConfigCode, errors.Alert, []string{"Grafana endpoint not configured"}, []string{"Cannot find valid grafana endpoint in user pref"}, []string{"Grafana endpoint might not be reachable from meshery"}, []string{"Setup your Grafana Endpoint via the settings dashboard"})
ErrStaticBoards = errors.New(ErrStaticBoardsCode, errors.Alert, []string{"unable to get static board"}, []string{"unable to get static board"}, []string{"No boards could be available in grafana"}, []string{})
ErrValidAdapter = errors.New(ErrValidAdapterCode, errors.Alert, []string{"Unable to find valid Adapter URL"}, []string{"unable to find a valid adapter for the given adapter URL"}, []string{"Given adapter URL is not valid"}, []string{"Please provide a valid Adapter URL"})
ErrAddAdapter = errors.New(ErrAddAdapterCode, errors.Alert, []string{"meshLocationURL is empty"}, []string{"meshLocationURL is empty to add an adapter"}, []string{"meshLocationURL cannot be empty to add an adapter"}, []string{"please provide the meshLocationURL"})
ErrMeshClient = errors.New(ErrMeshClientCode, errors.Alert, []string{"Error creating a mesh client", "Error pinging the mesh adapter"}, []string{"Unable to create a mesh client", "Unable to ping the mesh adapter"}, []string{"Adapter could not be pinged"}, []string{"Unable to connect to the Mesh adapter using the given config, please try again"})
ErrWriteResponse = errors.New(ErrWriteResponseCode, errors.Alert, []string{"Error writing response"}, []string{}, []string{}, []string{})
ErrTestConfigs = errors.New(ErrTestConfigsCode, errors.Alert, []string{"Error fetching test configs"}, []string{}, []string{}, []string{})
ErrInvalidGenValue = errors.New(ErrInvalidGenValueCode, errors.Alert, []string{"Invalid value for gen"}, []string{}, []string{}, []string{"please provide a valid value for gen (load generator)"})
ErrParseDuration = errors.New(ErrParseDurationCode, errors.Alert, []string{"error parsing test duration"}, []string{}, []string{"The format of the duration passed could be incorrect"}, []string{"please refer to: https://docs.meshery.io/guides/mesheryctl#performance-management"})
ErrInvalidK8SConfig = errors.New(ErrInvalidK8SConfigCode, errors.Alert, []string{"No valid kubernetes config found"}, []string{"Kubernetes config is not initialized with Meshery"}, []string{"Kubernetes config is not accessible to meshery or not valid"}, []string{"Upload your kubernetes config via the settings dashboard. If uploaded, wait for a minute for it to get initialized"})
ErrNilClient = errors.New(ErrNilClientCode, errors.Alert, []string{"Kubernetes client not initialized"}, []string{"Kubernetes config is not initialized with Meshery"}, []string{"Kubernetes config is not accessible to meshery or not valid"}, []string{"Upload your kubernetes config via the settings dashboard. If uploaded, wait for a minute for it to get initialized"})
ErrPrometheusConfig = errors.New(ErrPrometheusConfigCode, errors.Alert, []string{"Prometheus endpoint not configured"}, []string{"Cannot find valid Prometheus endpoint in user pref"}, []string{"Prometheus endpoint might not be reachable from meshery"}, []string{"Setup your Prometheus Endpoint via the settings dashboard"})
ErrGrafanaConfig = errors.New(ErrGrafanaConfigCode, errors.Alert, []string{"Grafana endpoint not configured"}, []string{"Cannot find valid grafana endpoint in user pref"}, []string{"Grafana endpoint might not be reachable from meshery"}, []string{"Setup your Grafana Endpoint via the settings dashboard"})
ErrStaticBoards = errors.New(ErrStaticBoardsCode, errors.Alert, []string{"unable to get static board"}, []string{"unable to get static board"}, []string{"No boards could be available in grafana"}, []string{})
ErrValidAdapter = errors.New(ErrValidAdapterCode, errors.Alert, []string{"Unable to find valid Adapter URL"}, []string{"unable to find a valid adapter for the given adapter URL"}, []string{"Given adapter URL is not valid"}, []string{"Please provide a valid Adapter URL"})
ErrAddAdapter = errors.New(ErrAddAdapterCode, errors.Alert, []string{"meshLocationURL is empty"}, []string{"meshLocationURL is empty to add an adapter"}, []string{"meshLocationURL cannot be empty to add an adapter"}, []string{"please provide the meshLocationURL"})
ErrMeshClient = errors.New(ErrMeshClientCode, errors.Alert, []string{"Error creating a mesh client", "Error pinging the mesh adapter"}, []string{"Unable to create a mesh client", "Unable to ping the mesh adapter"}, []string{"Adapter could not be pinged"}, []string{"Unable to connect to the Mesh adapter using the given config, please try again"})
ErrWriteResponse = errors.New(ErrWriteResponseCode, errors.Alert, []string{"Error writing response"}, []string{}, []string{}, []string{})
ErrTestConfigs = errors.New(ErrTestConfigsCode, errors.Alert, []string{"Error fetching test configs"}, []string{}, []string{}, []string{})
ErrInvalidGenValue = errors.New(ErrInvalidGenValueCode, errors.Alert, []string{"Invalid value for gen"}, []string{}, []string{}, []string{"please provide a valid value for gen (load generator)"})
ErrParseDuration = errors.New(ErrParseDurationCode, errors.Alert, []string{"error parsing test duration"}, []string{}, []string{"The format of the duration passed could be incorrect"}, []string{"please refer to: https://docs.meshery.io/guides/mesheryctl#performance-management"})
ErrMesheryInstanceID = errors.New(ErrMesheryInstanceIDCode, errors.Alert, []string{"Error: Meshery Instance ID is empty or is invalid"}, []string{}, []string{}, []string{})
)

func ErrPrometheusScan(err error) error {
Expand Down Expand Up @@ -344,6 +349,18 @@ func ErrChangeK8sContext(err error) error {
return errors.New(ErrCreateDirCode, errors.Alert, []string{"Error changing context"}, []string{err.Error()}, []string{"Context Name might be invalid or not present in the uploaded kubeconfig"}, []string{"Check the context name, if the context name is correct and is present in the kubeconfig then try uploading the kubeconfig again"})
}

func ErrInvalidKubeConfig(err error, content string) error {
return errors.New(ErrInvalidKubeConfigCode, errors.Alert, []string{"Invalid Kube Config ", content}, []string{err.Error()}, []string{"Meshery handler failed to find a valid kubernetes config for the deployment"}, []string{"Try uploading a new kubeconfig and also ensure that meshery can reach kubernetes API server"})
}

func ErrInvalidKubeHandler(err error, content string) error {
return errors.New(ErrInvalidKubeHandlerCode, errors.Alert, []string{"Invalid Kube Handler", content}, []string{err.Error()}, []string{"Meshery handler failed to find a valid kubernetes handler for the deployment"}, []string{"Try uploading a new kubeconfig and also ensure that meshery can reach kubernetes API server"})
}

func ErrInvalidKubeContext(err error, content string) error {
return errors.New(ErrInvalidKubeContextCode, errors.Alert, []string{"Invalid Kube Context", content}, []string{err.Error()}, []string{"Meshery handler failed to find a valid kubernetes context for the deployment"}, []string{"Try uploading a new kubeconfig and also ensure that meshery can reach kubernetes API server"})
}

func ErrSavingUserPreference(err error) error {
return errors.New(ErrSavingUserPreferenceCode, errors.Alert, []string{"Error saving user preference."}, []string{err.Error()}, []string{"Invalid data passed", "Unable to connect with provider"}, []string{"Pass valid values for preferences", "Make sure provider supports saving user preferences", "Make sure you're connected with provider", "Make sure extension provides these preferences"})
}
Expand Down