diff --git a/errors/errors.go b/errors/errors.go index ed807047..3c181602 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -2,13 +2,13 @@ package errors import "strings" -func NewDefault(code string, sdescription ...string) *Error { +func NewDefault(code string, ldescription ...string) *Error { return &Error{ Code: code, Severity: None, - ShortDescription: sdescription, - LongDescription: NoneString, + ShortDescription: NoneString, + LongDescription: ldescription, ProbableCause: NoneString, SuggestedRemediation: NoneString, } @@ -26,14 +26,14 @@ func New(code string, severity Severity, sdescription []string, ldescription []s } } -func (e *Error) Error() string { return strings.Join(e.LongDescription[:], ",") } +func (e *Error) Error() string { return strings.Join(e.LongDescription[:], ".") } func GetCode(err error) string { if obj := err.(*Error); obj != nil && obj.Code != " " { return obj.Code } - return strings.Join(NoneString[:], ",") + return strings.Join(NoneString[:], "") } func GetSeverity(err error) Severity { @@ -47,25 +47,25 @@ func GetSeverity(err error) Severity { func GetSDescription(err error) string { if obj := err.(*Error); obj != nil { - return strings.Join(err.(*Error).ShortDescription[:], ",") + return strings.Join(err.(*Error).ShortDescription[:], ".") } - return strings.Join(NoneString[:], ",") + return strings.Join(NoneString[:], "") } func GetCause(err error) string { if obj := err.(*Error); obj != nil { - return strings.Join(err.(*Error).ProbableCause[:], ",") + return strings.Join(err.(*Error).ProbableCause[:], ".") } - return strings.Join(NoneString[:], ",") + return strings.Join(NoneString[:], "") } func GetRemedy(err error) string { if obj := err.(*Error); obj != nil { - return strings.Join(err.(*Error).SuggestedRemediation[:], ",") + return strings.Join(err.(*Error).SuggestedRemediation[:], ".") } - return strings.Join(NoneString[:], ",") + return strings.Join(NoneString[:], "") } func Is(err error) (*Error, bool) { diff --git a/logger/logger.go b/logger/logger.go index 6d278df2..fb0d04ca 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -77,14 +77,14 @@ func (l *Logger) Error(err error) { } func (l *Logger) Info(description ...string) { - err := level.Info(l.infoHandler).Log("message", strings.Join(description, ",")) + err := level.Info(l.infoHandler).Log("message", strings.Join(description, "")) if err != nil { _ = l.errHandler.Log("Internal Logger Error") } } func (l *Logger) Debug(description ...string) { - err := level.Debug(l.infoHandler).Log("message", strings.Join(description, ",")) + err := level.Debug(l.infoHandler).Log("message", strings.Join(description, "")) if err != nil { _ = l.errHandler.Log("Internal Logger Error") } diff --git a/models/kubernetes.go b/models/kubernetes.go index 2bfc0ada..8b7d7964 100644 --- a/models/kubernetes.go +++ b/models/kubernetes.go @@ -2,7 +2,6 @@ package models import "time" -// Kubeconfig is structure of the kubeconfig file type Kubeconfig struct { APIVersion string `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"` Clusters []struct { diff --git a/utils/error.go b/utils/error.go index f7e704ca..f25f66de 100644 --- a/utils/error.go +++ b/utils/error.go @@ -1,15 +1,48 @@ package utils -import "github.com/layer5io/meshkit/errors" +import ( + "fmt" + "reflect" -func ErrUnmarshal(key string, err error) error { - return errors.NewDefault(errors.ErrUnmarshal, "Unmarshal error for key: "+key+", error: "+err.Error()) + "github.com/layer5io/meshkit/errors" +) + +func ErrUnmarshal(err error) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal unknown error: %s", err.Error())) +} + +func ErrUnmarshalInvalid(err error, typ reflect.Type) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal invalid error for type:%v, Error:%s", typ, err.Error())) +} + +func ErrUnmarshalUTF(err error, val string) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal invalid utf8 error for string:%s, Error:%s", val, err.Error())) +} + +func ErrUnmarshalSyntax(err error, offset int64) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal syntax error at offest: %d. Error: %s", offset, err.Error())) +} + +func ErrUnmarshalField(err error, key string) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal field error at key: %s. Error: %s", key, err.Error())) +} + +func ErrUnmarshalType(err error, value string) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal type error at key: %s. Error: %s", value, err.Error())) +} + +func ErrUnmarshalUnsupportedType(err error, typ reflect.Type) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal unsupported type error at key: %v. Error: %s", typ, err.Error())) +} + +func ErrUnmarshalUnsupportedValue(err error, value reflect.Value) error { + return errors.NewDefault(errors.ErrUnmarshal, fmt.Sprintf("Unmarshal unsupported value error at key: %v. Error: %s", value, err.Error())) } func ErrMarshal(err error) error { - return errors.NewDefault(errors.ErrMarshal, "Marshal error, Description: "+err.Error()) + return errors.NewDefault(errors.ErrMarshal, fmt.Sprintf("Marshal error, Description: %s", err.Error())) } func ErrGetBool(key string, err error) error { - return errors.NewDefault(errors.ErrGetBool, "Error while getting Boolean value for key: "+key+", error: "+err.Error()) + return errors.NewDefault(errors.ErrGetBool, fmt.Sprintf("Error while getting Boolean value for key: %s, error: %s", key, err.Error())) } diff --git a/utils/kubernetes/apply-manifest.go b/utils/kubernetes/apply-manifest.go index 9ce69999..189edb28 100644 --- a/utils/kubernetes/apply-manifest.go +++ b/utils/kubernetes/apply-manifest.go @@ -45,6 +45,11 @@ func (cfg *Config) ApplyManifest(contents []byte, options ApplyOptions) error { return ErrApplyManifest(err) } + val, err := meta.NewAccessor().Namespace(object) + if err == nil { + options.Namespace = val + } + if options.Delete { _, err = deleteObject(helper, options.Namespace, object) if err != nil { @@ -77,11 +82,6 @@ func constructObject(kubeClientset kubernetes.Interface, restConfig rest.Config, return nil, err } - _, err = meta.NewAccessor().Name(obj) - if err != nil { - return nil, err - } - // Create a client specifically for creating the object. restClient, err := newRestClient(restConfig, mapping.GroupVersionKind.GroupVersion()) if err != nil { diff --git a/utils/kubernetes/client.go b/utils/kubernetes/client.go new file mode 100644 index 00000000..c18c29b8 --- /dev/null +++ b/utils/kubernetes/client.go @@ -0,0 +1,8 @@ +package kubernetes + +func SetContext() error { + clientConfig, err := clientcmd.Load(kubeconfig) + if err != nil { + return + } +} diff --git a/utils/kubernetes/kubernetes.go b/utils/kubernetes/kubernetes.go index c3463890..27cb0bf5 100644 --- a/utils/kubernetes/kubernetes.go +++ b/utils/kubernetes/kubernetes.go @@ -1,11 +1,6 @@ package kubernetes import ( - "context" - - "github.com/layer5io/meshkit/utils" - coreV1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) @@ -21,104 +16,3 @@ func New(clientset kubernetes.Interface, cfg rest.Config) (*Config, error) { RestConfig: cfg, }, nil } - -// GetServiceEndpoint returns the endpoint for the given service -func (cfg *Config) GetServiceEndpoint(ctx context.Context, svcName, namespace string) (*utils.Endpoint, error) { - svc, err := cfg.Clientset.CoreV1().Services(namespace).Get(ctx, svcName, v1.GetOptions{}) - if err != nil { - return nil, ErrServiceDiscovery(err) - } - - // Try loadbalancer endpoint - if endpoint := extractLoadBalancerEndpoint(svc); endpoint != nil { - return endpoint, nil - } - - // Try nodeport endpoint - nodes, err := cfg.Clientset.CoreV1().Nodes().List(ctx, v1.ListOptions{}) - if err != nil { - return nil, ErrServiceDiscovery(err) - } - if endpoint := extractNodePortEndpoint(svc, nodes); endpoint != nil { - return endpoint, nil - } - - // Try clusterip endpoint - if endpoint := extractClusterIPEndpoint(svc); endpoint != nil { - return endpoint, nil - } - - return nil, err -} - -// extractLoadBalancerEndpoint extracts loadbalancer based endpoint, if any. -// It returns the nil if no valid endpoint is extracted -func extractLoadBalancerEndpoint(svc *coreV1.Service) *utils.Endpoint { - ports := svc.Spec.Ports - ingresses := svc.Status.LoadBalancer.Ingress - - for _, ingress := range ingresses { - var address string - if ingress.Hostname != "" && ingress.Hostname != "None" { - address = ingress.Hostname - } else if ingress.IP != "" { - address = ingress.IP - } else { - // If no valid ip address and hostname is found - // then move on to the next ingress - continue - } - - for _, port := range ports { - return &utils.Endpoint{ - Name: svc.GetName(), - Address: address, - Port: port.Port, - } - } - } - - return nil -} - -// extractNodePortEndpoint extracts nodeport based endpoint, if any. -// It returns the nil if no valid endpoint is extracted -func extractNodePortEndpoint(svc *coreV1.Service, nl *coreV1.NodeList) *utils.Endpoint { - ports := svc.Spec.Ports - - for _, node := range nl.Items { - for _, addressData := range node.Status.Addresses { - if addressData.Type == "InternalIP" { - address := addressData.Address - - for _, port := range ports { - // nodeport 0 is an invalid nodeport - if port.NodePort != 0 { - return &utils.Endpoint{ - Name: svc.GetName(), - Address: address, - Port: port.NodePort, - } - } - } - } - } - } - return nil -} - -// extractClusterIPEndpoint extracts clusterIP based endpoint, if any. -// It returns the nil if no valid endpoint is extracted -func extractClusterIPEndpoint(svc *coreV1.Service) *utils.Endpoint { - ports := svc.Spec.Ports - clusterIP := svc.Spec.ClusterIP - - for _, port := range ports { - return &utils.Endpoint{ - Name: svc.GetName(), - Address: clusterIP, - Port: port.Port, - } - } - return nil -} diff --git a/utils/kubernetes/service.go b/utils/kubernetes/service.go new file mode 100644 index 00000000..ff704a43 --- /dev/null +++ b/utils/kubernetes/service.go @@ -0,0 +1,110 @@ +package kubernetes + +import ( + "context" + + "github.com/layer5io/meshkit/utils" + coreV1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GetServiceEndpoint returns the endpoint for the given service +func (cfg *Config) GetServiceEndpoint(ctx context.Context, svcName, namespace string) (*utils.Endpoint, error) { + svc, err := cfg.Clientset.CoreV1().Services(namespace).Get(ctx, svcName, v1.GetOptions{}) + if err != nil { + return nil, ErrServiceDiscovery(err) + } + + // Try loadbalancer endpoint + if endpoint := extractLoadBalancerEndpoint(svc); endpoint != nil { + return endpoint, nil + } + + // Try nodeport endpoint + nodes, err := cfg.Clientset.CoreV1().Nodes().List(ctx, v1.ListOptions{}) + if err != nil { + return nil, ErrServiceDiscovery(err) + } + if endpoint := extractNodePortEndpoint(svc, nodes); endpoint != nil { + return endpoint, nil + } + + // Try clusterip endpoint + if endpoint := extractClusterIPEndpoint(svc); endpoint != nil { + return endpoint, nil + } + + return nil, err +} + +// extractLoadBalancerEndpoint extracts loadbalancer based endpoint, if any. +// It returns the nil if no valid endpoint is extracted +func extractLoadBalancerEndpoint(svc *coreV1.Service) *utils.Endpoint { + ports := svc.Spec.Ports + ingresses := svc.Status.LoadBalancer.Ingress + + for _, ingress := range ingresses { + var address string + if ingress.Hostname != "" && ingress.Hostname != "None" { + address = ingress.Hostname + } else if ingress.IP != "" { + address = ingress.IP + } else { + // If no valid ip address and hostname is found + // then move on to the next ingress + continue + } + + for _, port := range ports { + return &utils.Endpoint{ + Name: svc.GetName(), + Address: address, + Port: port.Port, + } + } + } + + return nil +} + +// extractNodePortEndpoint extracts nodeport based endpoint, if any. +// It returns the nil if no valid endpoint is extracted +func extractNodePortEndpoint(svc *coreV1.Service, nl *coreV1.NodeList) *utils.Endpoint { + ports := svc.Spec.Ports + + for _, node := range nl.Items { + for _, addressData := range node.Status.Addresses { + if addressData.Type == "InternalIP" { + address := addressData.Address + + for _, port := range ports { + // nodeport 0 is an invalid nodeport + if port.NodePort != 0 { + return &utils.Endpoint{ + Name: svc.GetName(), + Address: address, + Port: port.NodePort, + } + } + } + } + } + } + return nil +} + +// extractClusterIPEndpoint extracts clusterIP based endpoint, if any. +// It returns the nil if no valid endpoint is extracted +func extractClusterIPEndpoint(svc *coreV1.Service) *utils.Endpoint { + ports := svc.Spec.Ports + clusterIP := svc.Spec.ClusterIP + + for _, port := range ports { + return &utils.Endpoint{ + Name: svc.GetName(), + Address: clusterIP, + Port: port.Port, + } + } + return nil +} diff --git a/utils/utils.go b/utils/utils.go index 75a7e636..1dc2849c 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -20,7 +20,28 @@ func Unmarshal(obj string, result interface{}) error { obj = strings.TrimSpace(obj) err := json.Unmarshal([]byte(obj), result) if err != nil { - return ErrUnmarshal(obj, err) + if e, ok := err.(*json.SyntaxError); ok { + ErrUnmarshalSyntax(err, e.Offset) + } + if e, ok := err.(*json.UnmarshalFieldError); ok { + ErrUnmarshalField(err, e.Key) + } + if e, ok := err.(*json.UnmarshalTypeError); ok { + ErrUnmarshalType(err, e.Value) + } + if e, ok := err.(*json.UnsupportedTypeError); ok { + ErrUnmarshalUnsupportedType(err, e.Type) + } + if e, ok := err.(*json.UnsupportedValueError); ok { + ErrUnmarshalUnsupportedValue(err, e.Value) + } + if e, ok := err.(*json.InvalidUnmarshalError); ok { + ErrUnmarshalInvalid(err, e.Type) + } + if e, ok := err.(*json.InvalidUTF8Error); ok { + ErrUnmarshalUTF(err, e.S) + } + return ErrUnmarshal(err) } return nil }