mirror of
https://github.com/onepanelio/onepanel.git
synced 2025-09-27 01:56:03 +08:00
Merge pull request #959 from Vafilor/feat/create.namespace.stub
feat: stub out create namespace
This commit is contained in:
@@ -12,6 +12,7 @@ FROM golang:1.15.5
|
|||||||
COPY --from=builder /go/bin/core .
|
COPY --from=builder /go/bin/core .
|
||||||
COPY --from=builder /go/src/db ./db
|
COPY --from=builder /go/src/db ./db
|
||||||
COPY --from=builder /go/bin/goose .
|
COPY --from=builder /go/bin/goose .
|
||||||
|
COPY --from=builder /go/src/manifest ./manifest
|
||||||
|
|
||||||
EXPOSE 8888
|
EXPOSE 8888
|
||||||
EXPOSE 8887
|
EXPOSE 8887
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"title": "Onepanel",
|
"title": "Onepanel",
|
||||||
"description": "Onepanel API",
|
"description": "Onepanel API",
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"contact": {
|
"contact": {
|
||||||
"name": "Onepanel project",
|
"name": "Onepanel project",
|
||||||
"url": "https://github.com/onepanelio/core"
|
"url": "https://github.com/onepanelio/core"
|
||||||
@@ -4184,6 +4184,9 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sourceName": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -220,7 +220,8 @@ type Namespace struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
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() {
|
func (x *Namespace) Reset() {
|
||||||
@@ -262,6 +263,13 @@ func (x *Namespace) GetName() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Namespace) GetSourceName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.SourceName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var File_namespace_proto protoreflect.FileDescriptor
|
var File_namespace_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_namespace_proto_rawDesc = []byte{
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
|
||||||
|
@@ -40,4 +40,5 @@ message CreateNamespaceRequest {
|
|||||||
|
|
||||||
message Namespace {
|
message Namespace {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
|
string sourceName = 2;
|
||||||
}
|
}
|
0
manifest/.gitignore
vendored
Normal file
0
manifest/.gitignore
vendored
Normal file
@@ -174,6 +174,11 @@ func (s SystemConfig) DatabaseDriverName() *string {
|
|||||||
return s.GetValue("databaseDriverName")
|
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
|
// DatabaseConnection returns system config information to connect to a database
|
||||||
func (s SystemConfig) DatabaseConnection() (driverName, dataSourceName string) {
|
func (s SystemConfig) DatabaseConnection() (driverName, dataSourceName string) {
|
||||||
dataSourceName = fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=disable",
|
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
|
// by the CLI. CLI will marshal this struct into the correct
|
||||||
// YAML structure for k8s configmap / secret.
|
// YAML structure for k8s configmap / secret.
|
||||||
type ArtifactRepositoryS3Provider struct {
|
type ArtifactRepositoryS3Provider struct {
|
||||||
|
Source string
|
||||||
KeyFormat string `yaml:"keyFormat"`
|
KeyFormat string `yaml:"keyFormat"`
|
||||||
Bucket string
|
Bucket string
|
||||||
Endpoint string
|
Endpoint string
|
||||||
@@ -260,6 +266,7 @@ type ArtifactRepositoryS3Provider struct {
|
|||||||
// by the CLI. CLI will marshal this struct into the correct
|
// by the CLI. CLI will marshal this struct into the correct
|
||||||
// YAML structure for k8s configmap / secret.
|
// YAML structure for k8s configmap / secret.
|
||||||
type ArtifactRepositoryGCSProvider struct {
|
type ArtifactRepositoryGCSProvider struct {
|
||||||
|
Source string
|
||||||
KeyFormat string `yaml:"keyFormat"`
|
KeyFormat string `yaml:"keyFormat"`
|
||||||
Bucket string
|
Bucket string
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
43
pkg/istio.go
Normal file
43
pkg/istio.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVirtualService creates an istio virtual service
|
||||||
|
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
|
||||||
|
}
|
460
pkg/namespace.go
460
pkg/namespace.go
@@ -1,14 +1,39 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/onepanelio/core/pkg/util"
|
||||||
|
"github.com/onepanelio/core/pkg/util/data"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"io/ioutil"
|
||||||
|
vapps "k8s.io/api/apps/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
vnet "k8s.io/api/networking/v1"
|
||||||
|
v1rbac "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var onepanelEnabledLabelKey = "onepanel.io/enabled"
|
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) {
|
func (c *Client) ListOnepanelEnabledNamespaces() (namespaces []*Namespace, err error) {
|
||||||
namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{
|
namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{
|
||||||
LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"),
|
LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"),
|
||||||
@@ -42,6 +67,7 @@ func (c *Client) GetNamespace(name string) (namespace *Namespace, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListNamespaces lists all of the onepanel enabled namespaces
|
||||||
func (c *Client) ListNamespaces() (namespaces []*Namespace, err error) {
|
func (c *Client) ListNamespaces() (namespaces []*Namespace, err error) {
|
||||||
namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{
|
namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{
|
||||||
LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"),
|
LabelSelector: fmt.Sprintf("%s=%s", onepanelEnabledLabelKey, "true"),
|
||||||
@@ -60,25 +86,433 @@ func (c *Client) ListNamespaces() (namespaces []*Namespace, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) CreateNamespace(name string) (namespace *Namespace, err error) {
|
// CreateNamespace creates a namespace named {{ name }} assuming the {{ sourceNamespace }} created it
|
||||||
createNamespace := &v1.Namespace{
|
func (c *Client) CreateNamespace(sourceNamespace, name string) (namespace *Namespace, err error) {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
newNamespace := name
|
||||||
Name: name,
|
domain := *c.systemConfig.Domain()
|
||||||
Labels: map[string]string{
|
artifactRepositorySource, err := c.GetArtifactRepositorySource(sourceNamespace)
|
||||||
"istio-injection": "enabled",
|
if err != nil {
|
||||||
onepanelEnabledLabelKey: "true",
|
return nil, err
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
k8Namespace, err := c.CoreV1().Namespaces().Create(createNamespace)
|
config, err := c.GetNamespaceConfig(sourceNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
|
}
|
||||||
|
if config.ArtifactRepository.S3 == nil {
|
||||||
|
return nil, util.NewUserError(codes.Internal, "S3 compatible artifact repository not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
accessKey := config.ArtifactRepository.S3.AccessKey
|
||||||
|
secretKey := config.ArtifactRepository.S3.Secretkey
|
||||||
|
|
||||||
|
if err := c.createK8sNamespace(name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNetworkPolicy(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createIstioVirtualService(newNamespace, domain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createRole(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createDefaultSecret(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createSecretOnepanelDefaultNamespace(newNamespace, accessKey, secretKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createProviderDependentMinioDeployment(newNamespace, artifactRepositorySource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createProviderDependentMinioService(newNamespace, artifactRepositorySource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceConfigMap(sourceNamespace, newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceClusterRoleBinding(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceRoleBinding(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceServiceAccount(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceModelClusterRoleBinding(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.createNamespaceTemplates(newNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace = &Namespace{
|
namespace = &Namespace{
|
||||||
Name: k8Namespace.Name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) createK8sNamespace(name string) error {
|
||||||
|
createNamespace := &v1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"istio-injection": "enabled",
|
||||||
|
onepanelEnabledLabelKey: "true",
|
||||||
|
"app.kubernetes.io/component": "onepanel",
|
||||||
|
"app.kubernetes.io/instance": "onepanel-v0.5.0",
|
||||||
|
"app.kubernetes.io/managed-by": "onepanel-cli",
|
||||||
|
"app.kubernetes.io/name": "onepanel",
|
||||||
|
"app.kubernetes.io/part-of": "onepanel",
|
||||||
|
"app.kubernetes.io/version": "v0.5.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.CoreV1().Namespaces().Create(createNamespace)
|
||||||
|
if err != nil && strings.Contains(err.Error(), "already exists") {
|
||||||
|
return util.NewUserError(codes.AlreadyExists, "Namespace '"+name+"' already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNetworkPolicy(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "networkpolicy-onepanel-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
networkPolicy := &vnet.NetworkPolicy{}
|
||||||
|
if err := json.Unmarshal(data, networkPolicy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.NetworkingV1().NetworkPolicies(namespace).Create(networkPolicy)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createIstioVirtualService(namespace, domain string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
"$(applicationDomain)": domain,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "service-minio-onepanel.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
return c.CreateVirtualService(namespace, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createRole(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "role-onepanel-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
role := &v1rbac.Role{}
|
||||||
|
if err := json.Unmarshal(data, role); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.RbacV1().Roles(namespace).Create(role)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createDefaultSecret(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "secret-onepanel-default-env-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
secret := &v1.Secret{}
|
||||||
|
if err := json.Unmarshal(data, secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.CoreV1().Secrets(namespace).Create(secret)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createSecretOnepanelDefaultNamespace(namespace, accessKey, secretKey string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
"$(artifactRepositoryS3AccessKey)": base64.StdEncoding.EncodeToString([]byte(accessKey)),
|
||||||
|
"$(artifactRepositoryS3SecretKey)": base64.StdEncoding.EncodeToString([]byte(secretKey)),
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "secret-onepanel-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
secret := &v1.Secret{}
|
||||||
|
if err := json.Unmarshal(data, secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.CoreV1().Secrets(namespace).Create(secret)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createProviderDependentMinioDeployment(namespace, artifactRepositoryProvider string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
//// AWS S3 doesn't require a specific artifactRepositoryProvider
|
||||||
|
if artifactRepositoryProvider == "s3" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", artifactRepositoryProvider, "deployment.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
deployment := &vapps.Deployment{}
|
||||||
|
if err := json.Unmarshal(data, deployment); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.AppsV1().Deployments(namespace).Create(deployment)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createProviderDependentMinioService(namespace, artifactRepositoryProvider string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AWS S3 doesn't require a specific artifactRepositoryProvider
|
||||||
|
if artifactRepositoryProvider == "s3" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", artifactRepositoryProvider, "service.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
service := &v1.Service{}
|
||||||
|
if err := json.Unmarshal(data, service); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.CoreV1().Services(namespace).Create(service)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceClusterRoleBinding(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "clusterrolebinding-onepanel-namespaces-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
resource := &v1rbac.ClusterRoleBinding{}
|
||||||
|
if err := json.Unmarshal(data, resource); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Name += "-" + namespace
|
||||||
|
|
||||||
|
_, err = c.RbacV1().ClusterRoleBindings().Create(resource)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceRoleBinding(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "rolebinding-onepanel-defaultnamespace.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
resource := &v1rbac.RoleBinding{}
|
||||||
|
if err := json.Unmarshal(data, resource); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.RbacV1().RoleBindings(namespace).Create(resource)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceServiceAccount(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "service-account.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
resource := &v1.ServiceAccount{}
|
||||||
|
if err := json.Unmarshal(data, resource); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.CoreV1().ServiceAccounts(namespace).Create(resource)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceConfigMap(sourceNamespace, namespace string) error {
|
||||||
|
sourceConfigMap, err := c.CoreV1().ConfigMaps(sourceNamespace).Get("onepanel", metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := sourceConfigMap.Data["artifactRepository"]
|
||||||
|
sourceKey := "minio-gateway." + sourceNamespace + ".svc.cluster.local:9000"
|
||||||
|
replaceKey := "minio-gateway." + namespace + ".svc.cluster.local:9000"
|
||||||
|
data = strings.ReplaceAll(data, sourceKey, replaceKey)
|
||||||
|
sourceConfigMap.Data["artifactRepository"] = data
|
||||||
|
|
||||||
|
configMap := &v1.ConfigMap{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "onepanel",
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Data: sourceConfigMap.Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
configMap.Namespace = namespace
|
||||||
|
|
||||||
|
_, err = c.CoreV1().ConfigMaps(namespace).Create(configMap)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceModelClusterRoleBinding(namespace string) error {
|
||||||
|
replacements := map[string]string{
|
||||||
|
"$(applicationDefaultNamespace)": namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, err := replaceVariables(filepath.Join("manifest", "clusterrolebinding-models.json"), replacements)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := []byte(dataStr)
|
||||||
|
|
||||||
|
resource := &v1rbac.ClusterRoleBinding{}
|
||||||
|
if err := json.Unmarshal(data, resource); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.RbacV1().ClusterRoleBindings().Create(resource)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createNamespaceTemplates(namespace string) error {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
workflowDir := filepath.Join(wd, "db", "yaml")
|
||||||
|
|
||||||
|
filepaths := make([]string, 0)
|
||||||
|
|
||||||
|
err = filepath.Walk(workflowDir,
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if !info.IsDir() {
|
||||||
|
filepaths = append(filepaths, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range filepaths {
|
||||||
|
manifest, err := data.ManifestFileFromFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if manifest.Metadata.Kind == "Workflow" {
|
||||||
|
if manifest.Metadata.Action == "create" {
|
||||||
|
if err := c.createWorkflowTemplateFromGenericManifest(namespace, manifest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := c.updateWorkflowTemplateManifest(namespace, manifest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if manifest.Metadata.Kind == "Workspace" {
|
||||||
|
if manifest.Metadata.Action == "create" {
|
||||||
|
if err := c.createWorkspaceTemplateFromGenericManifest(namespace, manifest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := c.updateWorkspaceTemplateManifest(namespace, manifest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unknown manifest type for file %v", filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -105,6 +105,10 @@ func getClient(ctx context.Context, kubeConfig *v1.Config, db *v1.DB, sysConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsAuthorized(c *v1.Client, namespace, verb, group, resource, name string) (allowed bool, err error) {
|
func IsAuthorized(c *v1.Client, namespace, verb, group, resource, name string) (allowed bool, err error) {
|
||||||
|
if resource == "namespaces" && verb == "create" {
|
||||||
|
return false, status.Error(codes.PermissionDenied, "creating namespaces is not supported in the community edition")
|
||||||
|
}
|
||||||
|
|
||||||
review, err := c.AuthorizationV1().SelfSubjectAccessReviews().Create(&authorizationv1.SelfSubjectAccessReview{
|
review, err := c.AuthorizationV1().SelfSubjectAccessReviews().Create(&authorizationv1.SelfSubjectAccessReview{
|
||||||
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
|
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
|
||||||
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
ResourceAttributes: &authorizationv1.ResourceAttributes{
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthServer contains logic for checking Authorization of resources in the system
|
// 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")
|
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{
|
res = &api.GetAccessTokenResponse{
|
||||||
Domain: *domain,
|
Domain: *domain,
|
||||||
AccessToken: client.Token,
|
AccessToken: client.Token,
|
||||||
@@ -123,7 +141,7 @@ func (a *AuthServer) isValidToken(err error, client *v1.Client) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(namespaces) == 0 {
|
if len(namespaces) == 0 {
|
||||||
return errors.New("No namespaces for onepanel setup.")
|
return errors.New("no namespaces for onepanel setup")
|
||||||
}
|
}
|
||||||
namespace := namespaces[0]
|
namespace := namespaces[0]
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@ func apiNamespace(ns *v1.Namespace) (namespace *api.Namespace) {
|
|||||||
return
|
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) {
|
func (s *NamespaceServer) ListNamespaces(ctx context.Context, req *api.ListNamespacesRequest) (*api.ListNamespacesResponse, error) {
|
||||||
client := getClient(ctx)
|
client := getClient(ctx)
|
||||||
allowed, err := auth.IsAuthorized(client, "", "list", "", "namespaces", "")
|
allowed, err := auth.IsAuthorized(client, "", "list", "", "namespaces", "")
|
||||||
@@ -75,6 +76,7 @@ func (s *NamespaceServer) ListNamespaces(ctx context.Context, req *api.ListNames
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateNamespace creates a new namespace in the system
|
||||||
func (s *NamespaceServer) CreateNamespace(ctx context.Context, createNamespace *api.CreateNamespaceRequest) (*api.Namespace, error) {
|
func (s *NamespaceServer) CreateNamespace(ctx context.Context, createNamespace *api.CreateNamespaceRequest) (*api.Namespace, error) {
|
||||||
client := getClient(ctx)
|
client := getClient(ctx)
|
||||||
allowed, err := auth.IsAuthorized(client, "", "create", "", "namespaces", "")
|
allowed, err := auth.IsAuthorized(client, "", "create", "", "namespaces", "")
|
||||||
@@ -82,12 +84,13 @@ func (s *NamespaceServer) CreateNamespace(ctx context.Context, createNamespace *
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace, err := client.CreateNamespace(createNamespace.Namespace.Name)
|
namespace, err := client.CreateNamespace(createNamespace.Namespace.SourceName, createNamespace.Namespace.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &api.Namespace{
|
return &api.Namespace{
|
||||||
Name: namespace.Name,
|
Name: namespace.Name,
|
||||||
|
SourceName: createNamespace.Namespace.SourceName,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user