diff --git a/Dockerfile b/Dockerfile index cdb8db9..4db1f1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,7 @@ FROM golang:1.15.5 COPY --from=builder /go/bin/core . COPY --from=builder /go/src/db ./db COPY --from=builder /go/bin/goose . +COPY --from=builder /go/src/manifest ./manifest EXPOSE 8888 EXPOSE 8887 diff --git a/api/api.swagger.json b/api/api.swagger.json index b4e19b5..8e1cfe8 100644 --- a/api/api.swagger.json +++ b/api/api.swagger.json @@ -3,7 +3,7 @@ "info": { "title": "Onepanel", "description": "Onepanel API", - "version": "1.0.0", + "version": "1.0.2", "contact": { "name": "Onepanel project", "url": "https://github.com/onepanelio/core" @@ -4184,6 +4184,9 @@ "properties": { "name": { "type": "string" + }, + "sourceName": { + "type": "string" } } }, diff --git a/api/gen/namespace.pb.go b/api/gen/namespace.pb.go index 0ad6e6f..c74441f 100644 --- a/api/gen/namespace.pb.go +++ b/api/gen/namespace.pb.go @@ -220,7 +220,8 @@ type Namespace struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + SourceName string `protobuf:"bytes,2,opt,name=sourceName,proto3" json:"sourceName,omitempty"` } func (x *Namespace) Reset() { @@ -262,6 +263,13 @@ func (x *Namespace) GetName() string { return "" } +func (x *Namespace) GetSourceName() string { + if x != nil { + return x.SourceName + } + return "" +} + var File_namespace_proto protoreflect.FileDescriptor var file_namespace_proto_rawDesc = []byte{ @@ -289,9 +297,11 @@ var file_namespace_proto_rawDesc = []byte{ 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x1f, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x3f, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xec, 0x01, 0x0a, 0x10, 0x4e, 0x61, 0x6d, 0x65, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x32, 0xec, 0x01, 0x0a, 0x10, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, diff --git a/api/proto/namespace.proto b/api/proto/namespace.proto index f766f95..be52440 100644 --- a/api/proto/namespace.proto +++ b/api/proto/namespace.proto @@ -40,4 +40,5 @@ message CreateNamespaceRequest { message Namespace { string name = 1; + string sourceName = 2; } \ No newline at end of file diff --git a/manifest/.gitignore b/manifest/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/pkg/config_types.go b/pkg/config_types.go index 536817b..7251043 100644 --- a/pkg/config_types.go +++ b/pkg/config_types.go @@ -174,6 +174,11 @@ func (s SystemConfig) DatabaseDriverName() *string { return s.GetValue("databaseDriverName") } +// Provider gets the ONEPANEL_PROVIDER value, or nil. +func (s SystemConfig) Provider() *string { + return s.GetValue("ONEPANEL_PROVIDER") +} + // DatabaseConnection returns system config information to connect to a database func (s SystemConfig) DatabaseConnection() (driverName, dataSourceName string) { dataSourceName = fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable", @@ -243,6 +248,7 @@ func (s SystemConfig) HMACKey() []byte { // by the CLI. CLI will marshal this struct into the correct // YAML structure for k8s configmap / secret. type ArtifactRepositoryS3Provider struct { + Source string KeyFormat string `yaml:"keyFormat"` Bucket string Endpoint string @@ -260,6 +266,7 @@ type ArtifactRepositoryS3Provider struct { // by the CLI. CLI will marshal this struct into the correct // YAML structure for k8s configmap / secret. type ArtifactRepositoryGCSProvider struct { + Source string KeyFormat string `yaml:"keyFormat"` Bucket string Endpoint string diff --git a/pkg/istio.go b/pkg/istio.go new file mode 100644 index 0000000..0773fde --- /dev/null +++ b/pkg/istio.go @@ -0,0 +1,42 @@ +package v1 + +import ( + "fmt" + "github.com/onepanelio/core/pkg/util" + "google.golang.org/grpc/codes" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "strings" +) + +const istioVirtualServiceResource = "VirtualServices" + +func istioModelRestClient() (*rest.RESTClient, error) { + config := *NewConfig() + config.GroupVersion = &schema.GroupVersion{Group: "networking.istio.io", Version: "v1alpha3"} + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + return rest.RESTClientFor(&config) +} + +func (c *Client) CreateVirtualService(namespace string, data interface{}) error { + restClient, err := istioModelRestClient() + if err != nil { + return err + } + + err = restClient.Post(). + Namespace(namespace). + Resource(istioVirtualServiceResource). + Body(data). + Do(). + Error() + + if err != nil && strings.Contains(err.Error(), "already exists") { + return util.NewUserError(codes.AlreadyExists, fmt.Sprintf("VirtualService already exists")) + } + + return err +} diff --git a/pkg/namespace.go b/pkg/namespace.go index 38f731a..46a2921 100644 --- a/pkg/namespace.go +++ b/pkg/namespace.go @@ -2,13 +2,29 @@ package v1 import ( "fmt" - v1 "k8s.io/api/core/v1" - + "github.com/onepanelio/core/pkg/util" + "google.golang.org/grpc/codes" + "io/ioutil" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strings" ) var onepanelEnabledLabelKey = "onepanel.io/enabled" +func replaceVariables(filepath string, replacements map[string]string) (string, error) { + data, err := ioutil.ReadFile(filepath) + if err != nil { + return "", err + } + + dataStr := string(data) + for key, value := range replacements { + dataStr = strings.ReplaceAll(dataStr, key, value) + } + + return dataStr, nil +} + func (c *Client) ListOnepanelEnabledNamespaces() (namespaces []*Namespace, err error) { namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{ LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"), @@ -42,6 +58,7 @@ func (c *Client) GetNamespace(name string) (namespace *Namespace, err error) { return } +// ListNamespaces lists all of the onepanel enabled namespaces func (c *Client) ListNamespaces() (namespaces []*Namespace, err error) { namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{ LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"), @@ -60,25 +77,7 @@ func (c *Client) ListNamespaces() (namespaces []*Namespace, err error) { return } -func (c *Client) CreateNamespace(name string) (namespace *Namespace, err error) { - createNamespace := &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Labels: map[string]string{ - "istio-injection": "enabled", - onepanelEnabledLabelKey: "true", - }, - }, - } - - k8Namespace, err := c.CoreV1().Namespaces().Create(createNamespace) - if err != nil { - return - } - - namespace = &Namespace{ - Name: k8Namespace.Name, - } - - return +// CreateNamespace creates a new namespace in the system +func (c *Client) CreateNamespace(sourceNamespace, name string) (namespace *Namespace, err error) { + return nil, util.NewUserError(codes.FailedPrecondition, "Creating namespaces is not supported in the community edition") } diff --git a/server/auth_server.go b/server/auth_server.go index 354fa1f..d78129f 100644 --- a/server/auth_server.go +++ b/server/auth_server.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // AuthServer contains logic for checking Authorization of resources in the system @@ -73,6 +74,23 @@ func (a *AuthServer) GetAccessToken(ctx context.Context, req *api.GetAccessToken return nil, fmt.Errorf("domain is not set") } + // This is for backwards compatibility + // Originally, when you logged in as the admin, you would get the defaultNamespace as the + // namespace. + if req.Username == "admin" { + nsList, err := client.CoreV1().Namespaces().List(metav1.ListOptions{ + LabelSelector: "onepanel.io/defaultNamespace=true", + }) + + if err != nil { + return nil, err + } + + if len(nsList.Items) == 1 { + req.Username = nsList.Items[0].Name + } + } + res = &api.GetAccessTokenResponse{ Domain: *domain, AccessToken: client.Token, @@ -123,7 +141,7 @@ func (a *AuthServer) isValidToken(err error, client *v1.Client) error { return err } if len(namespaces) == 0 { - return errors.New("No namespaces for onepanel setup.") + return errors.New("no namespaces for onepanel setup.") } namespace := namespaces[0] diff --git a/server/namespace_server.go b/server/namespace_server.go index 9cd1d1d..d654a2a 100644 --- a/server/namespace_server.go +++ b/server/namespace_server.go @@ -28,6 +28,7 @@ func apiNamespace(ns *v1.Namespace) (namespace *api.Namespace) { return } +// ListNamespaces returns a list of all namespaces available in the system func (s *NamespaceServer) ListNamespaces(ctx context.Context, req *api.ListNamespacesRequest) (*api.ListNamespacesResponse, error) { client := getClient(ctx) allowed, err := auth.IsAuthorized(client, "", "list", "", "namespaces", "") @@ -75,6 +76,7 @@ func (s *NamespaceServer) ListNamespaces(ctx context.Context, req *api.ListNames }, nil } +// CreateNamespace creates a new namespace in the system func (s *NamespaceServer) CreateNamespace(ctx context.Context, createNamespace *api.CreateNamespaceRequest) (*api.Namespace, error) { client := getClient(ctx) allowed, err := auth.IsAuthorized(client, "", "create", "", "namespaces", "") @@ -82,12 +84,13 @@ func (s *NamespaceServer) CreateNamespace(ctx context.Context, createNamespace * return nil, err } - namespace, err := client.CreateNamespace(createNamespace.Namespace.Name) + namespace, err := client.CreateNamespace(createNamespace.Namespace.SourceName, createNamespace.Namespace.Name) if err != nil { return nil, err } return &api.Namespace{ - Name: namespace.Name, + Name: namespace.Name, + SourceName: createNamespace.Namespace.SourceName, }, nil }