소스 검색

install and create secret

sunguroku 2 년 전
부모
커밋
4cafbd98de

+ 101 - 0
api/server/handlers/doppler_integration/create_secret.go

@@ -0,0 +1,101 @@
+package doppler
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/telemetry"
+)
+
+type CreateDopplerSecretHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewCreateDopplerSecretHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *CreateDopplerSecretHandler {
+	return &CreateDopplerSecretHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+type CreateDopplerSecretHandlerRequest struct {
+	// Name of the env group to create or update
+	Name string `json:"name"`
+
+	// Doppler ServiceToken. Assigned per environment on Doppler.
+	ServiceToken string `json:"service_token"`
+}
+
+type CreateDopplerSecretHandlerResponse struct {
+	// Name of the env group to create or update
+	Name string `json:"name"`
+}
+
+func (c *CreateDopplerSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-create-doppler-secret")
+	defer span.End()
+
+	request := &CreateDopplerSecretHandlerRequest{}
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "doppler-group-name", Value: request.Name},
+	)
+
+	agent, err := c.GetAgent(r, cluster, "")
+	if err != nil {
+		err := telemetry.Error(ctx, span, err, "unable to connect to kubernetes cluster")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	data := map[string]string{
+		"serviceToken": request.ServiceToken,
+	}
+
+	secretData := EncodeSecrets(data)
+
+	// create secret first
+	if _, err := agent.CreateSecret(request.Name, "default", secretData); err != nil {
+
+		err := telemetry.Error(ctx, span, err, "unable to create secret")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	// Install Doppler CRD
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	dopplerSecretResponse := &CreateDopplerSecretHandlerResponse{
+		Name: request.Name,
+	}
+	c.WriteResult(w, r, dopplerSecretResponse)
+}
+
+func EncodeSecrets(data map[string]string) map[string][]byte {
+	res := make(map[string][]byte)
+
+	for key, rawValue := range data {
+		res[key] = []byte(rawValue)
+	}
+
+	return res
+}

+ 83 - 0
api/server/handlers/doppler_integration/install_operator.go

@@ -0,0 +1,83 @@
+package doppler
+
+import (
+	"context"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/authz"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/helm"
+	"github.com/porter-dev/porter/internal/helm/loader"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/telemetry"
+)
+
+const (
+	monitoringNodeLabel = "porter.run/workload-kind=monitoring"
+)
+
+type InstallDopplerHandler struct {
+	handlers.PorterHandlerReadWriter
+	authz.KubernetesAgentGetter
+}
+
+func NewInstallDopplerHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *InstallDopplerHandler {
+	return &InstallDopplerHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
+	}
+}
+
+func (c *InstallDopplerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-install-doppler-handler")
+	defer span.End()
+
+	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
+
+	helmAgent, err := c.GetHelmAgent(ctx, r, cluster, "default")
+	if err != nil {
+		err = telemetry.Error(ctx, span, err, "failed to get helm agent")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	chart, err := loader.LoadChartPublic(ctx, "https://helm.doppler.com", "doppler/doppler-kubernetes-operator", "")
+	if err != nil {
+		err = telemetry.Error(ctx, span, err, "failed load public doppler operator chart")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	// create namespace if not exists
+	_, err = helmAgent.K8sAgent.CreateNamespace("doppler", nil)
+	if err != nil {
+		err = telemetry.Error(ctx, span, err, "failed to create doppler namespace")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	conf := &helm.InstallChartConfig{
+		Chart:     chart,
+		Name:      "doppler",
+		Namespace: "doppler",
+		Cluster:   cluster,
+		Repo:      c.Repo(),
+	}
+
+	_, err = helmAgent.InstallChart(context.Background(), conf, c.Config().DOConf, c.Config().ServerConf.DisablePullSecretsInjection)
+	if err != nil {
+		err = telemetry.Error(ctx, span, err, "error installing doppler operator")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+}

+ 8 - 0
api/types/crd.go

@@ -1,5 +1,13 @@
 package types
 package types
 
 
+type CreateCRDRequest struct {
+	Name      string `schema:"name" form:"required"`
+	Namespace string `schema:"namespace" form:"required"`
+	Group     string `schema:"group" form:"required"`
+	Version   string `schema:"version" form:"required"`
+	Resource  string `schema:"resource" form`
+}
+
 type DeleteCRDRequest struct {
 type DeleteCRDRequest struct {
 	Name      string `schema:"name" form:"required"`
 	Name      string `schema:"name" form:"required"`
 	Namespace string `schema:"namespace" form:"required"`
 	Namespace string `schema:"namespace" form:"required"`

+ 1 - 1
dashboard/src/components/CredentialsForm.tsx

@@ -188,7 +188,7 @@ const CredentialsForm: React.FC<Props> = ({
         <HSpacer />
         <HSpacer />
         <Img src={aws} />
         <Img src={aws} />
         Set AWS credentials
         Set AWS credentials
-        <HelperButton onClick={() => window.open("https://docs.porter.run/standard/getting-started/provisioning-on-aws", "_blank")}>
+        <HelperButton onClick={() => window.open("https://docs.porter.run/provision/provisioning-on-aws", "_blank")}>
           <i className="material-icons">help_outline</i>
           <i className="material-icons">help_outline</i>
         </HelperButton>
         </HelperButton>
       </Text>
       </Text>

+ 1 - 1
dashboard/src/components/GCPCredentialsForm.tsx

@@ -157,7 +157,7 @@ const GCPCredentialsForm: React.FC<Props> = ({ goBack, proceed }) => {
           <>
           <>
             <Text size={16}> Create the service account </Text>
             <Text size={16}> Create the service account </Text>
             <Spacer y={.5} />
             <Spacer y={.5} />
-            <Link onClick={incrementStep} to="https://docs.porter.run/standard/getting-started/provisioning-on-gcp" target="_blank">
+            <Link onClick={incrementStep} to="https://docs.porter.run/provision/provisioning-on-gcp" target="_blank">
               Follow the steps in the Porter docs to generate your service account credentials
               Follow the steps in the Porter docs to generate your service account credentials
             </Link>
             </Link>
             <Spacer y={.5} />
             <Spacer y={.5} />

+ 1 - 1
dashboard/src/components/porter-form/field-components/CronInput.tsx

@@ -60,7 +60,7 @@ const CronInput: React.FC<CronField> = (props) => {
             click{" "}
             click{" "}
             <DynamicLink
             <DynamicLink
               style={{ color: "red", textDecoration: "underline" }}
               style={{ color: "red", textDecoration: "underline" }}
-              to="https://docs.porter.run/running-jobs/deploying-jobs#deploying-a-cron-job"
+              to="https://docs.porter.run/deploy/types-of-services#jobs-and-cron-jobs"
             >
             >
               here
               here
             </DynamicLink>
             </DynamicLink>

+ 2 - 2
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/FormFlow.tsx

@@ -42,12 +42,12 @@ const FormTitle = {
   aws: {
   aws: {
     label: "Amazon Web Services (AWS)",
     label: "Amazon Web Services (AWS)",
     icon: integrationList["aws"].icon,
     icon: integrationList["aws"].icon,
-    doc: "https://docs.porter.run/getting-started/provisioning-on-aws",
+    doc: "https://docs.porter.run/provision/provisioning-on-aws",
   },
   },
   gcp: {
   gcp: {
     label: "Google Cloud Platform (GCP)",
     label: "Google Cloud Platform (GCP)",
     icon: integrationList["gcp"].icon,
     icon: integrationList["gcp"].icon,
-    doc: "https://docs.porter.run/getting-started/provisioning-on-gcp",
+    doc: "https://docs.porter.run/provision/provisioning-on-gcp",
   },
   },
   external: {
   external: {
     label: "Connect an existing cluster",
     label: "Connect an existing cluster",

+ 15 - 0
internal/kubernetes/agent.go

@@ -254,6 +254,21 @@ func (a *Agent) CreateLinkedSecret(name, namespace, cmName string, data map[stri
 	)
 	)
 }
 }
 
 
+// CreateSecret creates any generic secret given the key-value pairs and namespace. Values are
+func (a *Agent) CreateSecret(name string, namespace string, data map[string][]byte) (*v1.Secret, error) {
+	return a.Clientset.CoreV1().Secrets(namespace).Create(
+		context.TODO(),
+		&v1.Secret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      name,
+				Namespace: namespace,
+			},
+			Data: data,
+		},
+		metav1.CreateOptions{},
+	)
+}
+
 type mergeConfigMapData struct {
 type mergeConfigMapData struct {
 	Data map[string]*string `json:"data"`
 	Data map[string]*string `json:"data"`
 }
 }