Просмотр исходного кода

Merge pull request #187 from porter-dev/master

merge master into staging
abelanger5 5 лет назад
Родитель
Сommit
47f67ec1ea

+ 0 - 0
.github/workflows/gcr.yaml → .github/workflows/staging.yaml


+ 1 - 1
README.md

@@ -1,5 +1,5 @@
 # Porter 
 # Porter 
-[![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) [![Go Report Card](https://goreportcard.com/badge/gojp/goreportcard)](https://goreportcard.com/report/gojp/goreportcard)
+[![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) [![Go Report Card](https://goreportcard.com/badge/gojp/goreportcard)](https://goreportcard.com/report/github.com/porter-dev/porter)
 
 
 **Porter is a Kubernetes-powered PaaS that runs in your own cloud provider.** Porter brings the Heroku experience to Kubernetes without compromising its flexibility. Get started on Porter without the overhead of DevOps and fully customize your infra later when you need to.
 **Porter is a Kubernetes-powered PaaS that runs in your own cloud provider.** Porter brings the Heroku experience to Kubernetes without compromising its flexibility. Get started on Porter without the overhead of DevOps and fully customize your infra later when you need to.
 
 

+ 5 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx

@@ -33,7 +33,7 @@ export default class Logs extends Component<PropsType, StateType> {
       return <Message>No logs to display from this pod.</Message>
       return <Message>No logs to display from this pod.</Message>
     }
     }
     return this.state.logs.map((log, i) => {
     return this.state.logs.map((log, i) => {
-        return <div key={i}>{log}</div>
+        return <Log key={i}>{log}</Log>
     })
     })
   }
   }
 
 
@@ -106,4 +106,8 @@ const Message = styled.div`
   justify-content: center;
   justify-content: center;
   color: #ffffff44;
   color: #ffffff44;
   font-size: 13px;
   font-size: 13px;
+`;
+
+const Log = styled.div`
+  font-family: monospace;
 `;
 `;

+ 1 - 0
dashboard/src/main/home/new-project/NewProject.tsx

@@ -313,6 +313,7 @@ export default class NewProject extends Component<PropsType, StateType> {
           
           
           if (this.state.selectedProvider === 'aws') {
           if (this.state.selectedProvider === 'aws') {
             this.provisionECR(proj, this.provisionEKS)
             this.provisionECR(proj, this.provisionEKS)
+
           } else {
           } else {
             this.props.setCurrentView('dashboard', null);
             this.props.setCurrentView('dashboard', null);
           }
           }

+ 112 - 83
dashboard/src/main/home/new-project/Provisioner.tsx

@@ -15,7 +15,7 @@ import { inflateRaw, inflateRawSync } from 'zlib';
 type PropsType = {
 type PropsType = {
   viewData: any,
   viewData: any,
   setCurrentView: (x: string) => void,
   setCurrentView: (x: string) => void,
-};
+}
 
 
 type StateType = {
 type StateType = {
   error: boolean,
   error: boolean,
@@ -23,6 +23,7 @@ type StateType = {
   websockets: any[],
   websockets: any[],
   maxStep : Record<string, number>,
   maxStep : Record<string, number>,
   currentStep: Record<string, number>,
   currentStep: Record<string, number>,
+  triggerEnd: boolean,
 };
 };
 
 
 export default class Provisioner extends Component<PropsType, StateType> {
 export default class Provisioner extends Component<PropsType, StateType> {
@@ -32,6 +33,7 @@ export default class Provisioner extends Component<PropsType, StateType> {
     websockets : [] as any[],
     websockets : [] as any[],
     maxStep: {} as Record<string, any>,
     maxStep: {} as Record<string, any>,
     currentStep: {} as Record<string, number>,
     currentStep: {} as Record<string, number>,
+    triggerEnd: false,
   }
   }
 
 
   scrollToBottom = () => {
   scrollToBottom = () => {
@@ -47,99 +49,102 @@ export default class Provisioner extends Component<PropsType, StateType> {
     return true;
     return true;
   }
   }
 
 
-  componentDidMount() {
-    let { currentProject } = this.context;
-    let protocol = process.env.NODE_ENV == 'production' ? 'wss' : 'ws'
-    let viewData = this.props.viewData || []
+  setupWebsocket = (ws: WebSocket, infra: any) => {
+    ws.onopen = () => {
+      console.log('connected to websocket')
+    }
 
 
-    let websockets = viewData.map((infra: any) => {
-      let ws = new WebSocket(`${protocol}://${process.env.API_SERVER}/api/projects/${currentProject.id}/provision/${infra.kind}/${infra.infra_id}/logs`)
+    ws.onmessage = (evt: MessageEvent) => {
+      let event = JSON.parse(evt.data);
+      let validEvents = [] as any[];
+      let err = null;
       
       
-      ws.onopen = () => {
-        console.log('connected to websocket')
-      }
+      for (var i = 0; i < event.length; i++) {
+        let msg = event[i];
+        if (msg["Values"] && msg["Values"]["data"] && this.isJSON(msg["Values"]["data"])) { 
+          let d = JSON.parse(msg["Values"]["data"]);
+
+          if (d["kind"] == "error") {
+            err = d["log"];
+            break;
+          }
 
 
-      ws.onmessage = (evt: MessageEvent) => {
-        let event = JSON.parse(evt.data);
-        let validEvents = [] as any[];
-        let err = null;
-        
-        for (var i = 0; i < event.length; i++) {
-          let msg = event[i];
-          if (msg["Values"] && msg["Values"]["data"] && this.isJSON(msg["Values"]["data"])) { 
-            let d = JSON.parse(msg["Values"]["data"]);
-  
-            if (d["kind"] == "error") {
-              err = d["log"];
-              break;
-            }
-  
-            // add only valid events
-            if (d["log"] != null && d["created_resources"] != null && d["total_resources"] != null) {
-              validEvents.push(d);
-            }
+          // add only valid events
+          if (d["log"] != null && d["created_resources"] != null && d["total_resources"] != null) {
+            validEvents.push(d);
           }
           }
         }
         }
-  
-        if (err) {
-          let e = ansiparse(err).map((el: any) => {
-            return el.text;
-          })
-          this.setState({ logs: e, error: true });
-          return;
-        }
-  
-        if (validEvents.length == 0) {
-          return;
-        }
-        
-        if (!this.state.maxStep[infra.kind] || !this.state.maxStep[infra.kind]["total_resources"]) {
-          this.setState({
-            maxStep: {
-              ...this.state.maxStep,
-              [infra.kind] : validEvents[validEvents.length - 1]["total_resources"]
-            }
-          })
-        }
-        
-        let logs = [] as any[]
-        validEvents.forEach((e: any) => {
-          logs.push(...ansiparse(e["log"]))
-        })
+      }
 
 
-        logs = logs.map((log: any) => {
-          return log.text
-        })
-  
-        this.setState({ 
-          logs: [...this.state.logs, ...logs], 
-          currentStep: {
-            ...this.state.currentStep,
-            [infra.kind] : validEvents[validEvents.length - 1]["created_resources"]
-          },
-        }, () => {
-          this.scrollToBottom()
+      if (err) {
+        let e = ansiparse(err).map((el: any) => {
+          return el.text;
         })
         })
+        this.setState({ logs: e, error: true });
+        return;
       }
       }
 
 
-      ws.onerror = (err: ErrorEvent) => {
-        console.log(err)
+      if (validEvents.length == 0) {
+        return;
       }
       }
-
-      ws.onclose = () => {
-        console.log('closing provisioner websocket')
+      
+      if (!this.state.maxStep[infra.kind] || !this.state.maxStep[infra.kind]["total_resources"]) {
+        this.setState({
+          maxStep: {
+            ...this.state.maxStep,
+            [infra.kind] : validEvents[validEvents.length - 1]["total_resources"]
+          }
+        })
       }
       }
+      
+      let logs = [] as any[]
+      validEvents.forEach((e: any) => {
+        logs.push(...ansiparse(e["log"]))
+      })
+
+      logs = logs.map((log: any) => {
+        return log.text
+      })
+
+      this.setState({ 
+        logs: [...this.state.logs, ...logs], 
+        currentStep: {
+          ...this.state.currentStep,
+          [infra.kind] : validEvents[validEvents.length - 1]["created_resources"]
+        },
+      }, () => {
+        this.scrollToBottom()
+      })
+    }
+
+    ws.onerror = (err: ErrorEvent) => {
+      console.log(err)
+    }
+
+    ws.onclose = () => {
+      console.log('closing provisioner websocket')
+    }
 
 
-      return ws
+    return ws
+  }
+
+  componentDidMount() {
+    let { currentProject } = this.context;
+    let protocol = process.env.NODE_ENV == 'production' ? 'wss' : 'ws'
+    let viewData = this.props.viewData || []
+
+    let websockets = viewData.map((infra: any) => {
+      let ws = new WebSocket(`${protocol}://${process.env.API_SERVER}/api/projects/${currentProject.id}/provision/${infra.kind}/${infra.infra_id}/logs`)
+      return this.setupWebsocket(ws, infra)
     });
     });
 
 
-    this.setState({ websockets, logs: [] });
+    this.setState({ websockets, logs: ["Provisioning EKS cluster and ECR registry..."] });
   }
   }
 
 
   componentWillUnmount() {
   componentWillUnmount() {
     if (!this.state.websockets) { return; }
     if (!this.state.websockets) { return; }
 
 
-    this.state.websockets.forEach((ws) => {
+    this.state.websockets.forEach((ws: any) => {
       ws.close()
       ws.close()
     })
     })
   }
   }
@@ -148,7 +153,7 @@ export default class Provisioner extends Component<PropsType, StateType> {
 
 
   renderLogs = () => {
   renderLogs = () => {
     return this.state.logs.map((log, i) => {
     return this.state.logs.map((log, i) => {
-      return <div key={i}>{log}</div>
+      return <Log key={i}>{log}</Log>
     });
     });
   }
   }
 
 
@@ -183,24 +188,44 @@ export default class Provisioner extends Component<PropsType, StateType> {
       </>
       </>
     )
     )
   }
   }
+
+  onEnd = () => {
+    let myInterval = setInterval(() => {
+      console.log('interval')
+      api.getClusters('<token>', {}, { id: this.context.currentProject.id }, (err: any, res: any) => {
+        if (err) {
+          console.log(err);
+        } else if (res.data) {
+          let clusters = res.data;
+          console.log('found clusters:', res.data);
+          if (clusters.length > 0) {
+            this.props.setCurrentView('dashboard');
+            clearInterval(myInterval);
+          }
+        }
+      });
+    }, 1000);
+  }
   
   
   render() {
   render() {
     let maxStep = 0;
     let maxStep = 0;
     let currentStep = 0;
     let currentStep = 0;
 
 
     for (let key in this.state.maxStep) {
     for (let key in this.state.maxStep) {
-      console.log(key)
-      maxStep += this.state.maxStep[key]
+      if (key == 'eks') {
+        maxStep += this.state.maxStep[key]
+      }
     }
     }
 
 
     for (let key in this.state.currentStep) {
     for (let key in this.state.currentStep) {
-      currentStep += this.state.currentStep[key]
+      if (key == 'eks') {
+        currentStep += this.state.currentStep[key]
+      }
     }
     }
 
 
-    if (maxStep !== 0 && currentStep === maxStep) {
-      console.log('Thinks provisioning complete.')
-      console.log(currentStep, maxStep);
-      this.props.setCurrentView('dashboard');
+    if (maxStep !== 0 && currentStep === maxStep && !this.state.triggerEnd) {
+      this.onEnd()
+      this.setState({ triggerEnd: true });
     }
     }
 
 
     return (
     return (
@@ -246,6 +271,10 @@ const Wrapper = styled.div`
   padding: 20px 25px;
   padding: 20px 25px;
 `;
 `;
 
 
+const Log = styled.div`
+  font-family: monospace;
+`;
+
 const LogStream = styled.div`
 const LogStream = styled.div`
   height: 300px;
   height: 300px;
   margin-top: 30px;
   margin-top: 30px;

+ 3 - 0
dashboard/src/main/home/sidebar/ClusterSection.tsx

@@ -53,6 +53,7 @@ export default class ClusterSection extends Component<PropsType, StateType> {
         // TODO: handle uninitialized kubeconfig
         // TODO: handle uninitialized kubeconfig
         if (res.data) {
         if (res.data) {
           let clusters = res.data;
           let clusters = res.data;
+          console.log('found clusters:', res.data);
           if (clusters.length > 0) {
           if (clusters.length > 0) {
             this.setState({ clusters });
             this.setState({ clusters });
             setCurrentCluster(clusters[0]);
             setCurrentCluster(clusters[0]);
@@ -69,6 +70,7 @@ export default class ClusterSection extends Component<PropsType, StateType> {
 
 
   componentDidMount() {
   componentDidMount() {
     this.updateClusters();
     this.updateClusters();
+    console.log('mounted clustersection');
   }
   }
 
 
   // Need to override showDrawer when the sidebar is closed
   // Need to override showDrawer when the sidebar is closed
@@ -82,6 +84,7 @@ export default class ClusterSection extends Component<PropsType, StateType> {
       } else if (this.props.forceRefreshClusters === true) {
       } else if (this.props.forceRefreshClusters === true) {
         this.updateClusters();
         this.updateClusters();
         this.props.setRefreshClusters(false);
         this.props.setRefreshClusters(false);
+        console.log('hard refereshed clusters');
       }
       }
 
 
       if (this.props.forceCloseDrawer && this.state.showDrawer) {
       if (this.props.forceCloseDrawer && this.state.showDrawer) {

+ 14 - 11
internal/kubernetes/agent.go

@@ -7,7 +7,6 @@ import (
 	"io"
 	"io"
 	"strings"
 	"strings"
 
 
-	"github.com/porter-dev/porter/internal/config"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws/ecr"
 	"github.com/porter-dev/porter/internal/kubernetes/provisioner/aws/ecr"
@@ -26,6 +25,8 @@ import (
 	"k8s.io/client-go/informers"
 	"k8s.io/client-go/informers"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/client-go/tools/cache"
+
+	"github.com/porter-dev/porter/internal/config"
 )
 )
 
 
 // Agent is a Kubernetes agent for performing operations that interact with the
 // Agent is a Kubernetes agent for performing operations that interact with the
@@ -240,6 +241,8 @@ func (a *Agent) ProvisionECR(
 	ecrName string,
 	ecrName string,
 	awsInfra *models.AWSInfra,
 	awsInfra *models.AWSInfra,
 	operation provisioner.ProvisionerOperation,
 	operation provisioner.ProvisionerOperation,
+	pgConf *config.DBConf,
+	redisConf *config.RedisConf,
 ) (*batchv1.Job, error) {
 ) (*batchv1.Job, error) {
 	id := awsInfra.GetID()
 	id := awsInfra.GetID()
 	prov := &provisioner.Conf{
 	prov := &provisioner.Conf{
@@ -247,6 +250,8 @@ func (a *Agent) ProvisionECR(
 		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
 		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
 		Kind:      provisioner.ECR,
 		Kind:      provisioner.ECR,
 		Operation: operation,
 		Operation: operation,
+		Redis:     redisConf,
+		Postgres:  pgConf,
 		AWS: &aws.Conf{
 		AWS: &aws.Conf{
 			AWSRegion:          awsConf.AWSRegion,
 			AWSRegion:          awsConf.AWSRegion,
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
@@ -267,6 +272,8 @@ func (a *Agent) ProvisionEKS(
 	eksName string,
 	eksName string,
 	awsInfra *models.AWSInfra,
 	awsInfra *models.AWSInfra,
 	operation provisioner.ProvisionerOperation,
 	operation provisioner.ProvisionerOperation,
+	pgConf *config.DBConf,
+	redisConf *config.RedisConf,
 ) (*batchv1.Job, error) {
 ) (*batchv1.Job, error) {
 	id := awsInfra.GetID()
 	id := awsInfra.GetID()
 	prov := &provisioner.Conf{
 	prov := &provisioner.Conf{
@@ -274,6 +281,8 @@ func (a *Agent) ProvisionEKS(
 		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
 		Name:      fmt.Sprintf("prov-%s-%s", id, string(operation)),
 		Kind:      provisioner.EKS,
 		Kind:      provisioner.EKS,
 		Operation: provisioner.Apply,
 		Operation: provisioner.Apply,
+		Redis:     redisConf,
+		Postgres:  pgConf,
 		AWS: &aws.Conf{
 		AWS: &aws.Conf{
 			AWSRegion:          awsConf.AWSRegion,
 			AWSRegion:          awsConf.AWSRegion,
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
 			AWSAccessKeyID:     string(awsConf.AWSAccessKeyID),
@@ -291,12 +300,16 @@ func (a *Agent) ProvisionEKS(
 func (a *Agent) ProvisionTest(
 func (a *Agent) ProvisionTest(
 	projectID uint,
 	projectID uint,
 	operation provisioner.ProvisionerOperation,
 	operation provisioner.ProvisionerOperation,
+	pgConf *config.DBConf,
+	redisConf *config.RedisConf,
 ) (*batchv1.Job, error) {
 ) (*batchv1.Job, error) {
 	prov := &provisioner.Conf{
 	prov := &provisioner.Conf{
 		ID:        fmt.Sprintf("%s-%d", "testing", projectID),
 		ID:        fmt.Sprintf("%s-%d", "testing", projectID),
 		Name:      fmt.Sprintf("prov-%s-%d-%s", "testing", projectID, string(operation)),
 		Name:      fmt.Sprintf("prov-%s-%d-%s", "testing", projectID, string(operation)),
 		Operation: provisioner.Apply,
 		Operation: provisioner.Apply,
 		Kind:      provisioner.Test,
 		Kind:      provisioner.Test,
+		Redis:     redisConf,
+		Postgres:  pgConf,
 	}
 	}
 
 
 	return a.provision(prov)
 	return a.provision(prov)
@@ -307,16 +320,6 @@ func (a *Agent) provision(
 ) (*batchv1.Job, error) {
 ) (*batchv1.Job, error) {
 	prov.Namespace = "default"
 	prov.Namespace = "default"
 
 
-	prov.Redis = &config.RedisConf{
-		Host: "redis-master.default.svc.cluster.local",
-		Port: "6379",
-	}
-
-	prov.Postgres = &provisioner.PostgresConf{
-		Host: "postgres-postgresql.default.svc.cluster.local",
-		Port: "5432",
-	}
-
 	job, err := prov.GetProvisionerJobTemplate()
 	job, err := prov.GetProvisionerJobTemplate()
 
 
 	if err != nil {
 	if err != nil {

+ 18 - 28
internal/kubernetes/provisioner/provisioner.go

@@ -1,6 +1,8 @@
 package provisioner
 package provisioner
 
 
 import (
 import (
+	"fmt"
+
 	batchv1 "k8s.io/api/batch/v1"
 	batchv1 "k8s.io/api/batch/v1"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -29,7 +31,7 @@ type Conf struct {
 	Namespace string
 	Namespace string
 	ID        string
 	ID        string
 	Redis     *config.RedisConf
 	Redis     *config.RedisConf
-	Postgres  *PostgresConf
+	Postgres  *config.DBConf
 	Operation ProvisionerOperation
 	Operation ProvisionerOperation
 
 
 	// provider-specific configurations
 	// provider-specific configurations
@@ -38,12 +40,6 @@ type Conf struct {
 	EKS *eks.Conf
 	EKS *eks.Conf
 }
 }
 
 
-// PostgresConf is the postgres config for the provisioner container
-type PostgresConf struct {
-	Host string
-	Port string
-}
-
 type ProvisionerOperation string
 type ProvisionerOperation string
 
 
 const (
 const (
@@ -170,19 +166,20 @@ func (conf *Conf) addRedisEnv(env []v1.EnvVar) []v1.EnvVar {
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
 		Name:  "REDIS_USER",
 		Name:  "REDIS_USER",
-		Value: "default",
+		Value: conf.Redis.Username,
 	})
 	})
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
-		Name: "REDIS_PASS",
-		ValueFrom: &v1.EnvVarSource{
-			SecretKeyRef: &v1.SecretKeySelector{
-				LocalObjectReference: v1.LocalObjectReference{
-					Name: "redis",
-				},
-				Key: "redis-password",
-			},
-		},
+		Name:  "REDIS_PASS",
+		Value: conf.Redis.Password,
+		// ValueFrom: &v1.EnvVarSource{
+		// 	SecretKeyRef: &v1.SecretKeySelector{
+		// 		LocalObjectReference: v1.LocalObjectReference{
+		// 			Name: "redis",
+		// 		},
+		// 		Key: "redis-password",
+		// 	},
+		// },
 	})
 	})
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
@@ -202,24 +199,17 @@ func (conf *Conf) addPostgresEnv(env []v1.EnvVar) []v1.EnvVar {
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
 		Name:  "PG_PORT",
 		Name:  "PG_PORT",
-		Value: conf.Postgres.Port,
+		Value: fmt.Sprintf("%d", conf.Postgres.Port),
 	})
 	})
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
 		Name:  "PG_USER",
 		Name:  "PG_USER",
-		Value: "postgres",
+		Value: conf.Postgres.Username,
 	})
 	})
 
 
 	env = append(env, v1.EnvVar{
 	env = append(env, v1.EnvVar{
-		Name: "PG_PASS",
-		ValueFrom: &v1.EnvVarSource{
-			SecretKeyRef: &v1.SecretKeySelector{
-				LocalObjectReference: v1.LocalObjectReference{
-					Name: "postgres-postgresql",
-				},
-				Key: "postgresql-password",
-			},
-		},
+		Name:  "PG_PASS",
+		Value: conf.Postgres.Password,
 	})
 	})
 
 
 	return env
 	return env

Разница между файлами не показана из-за своего большого размера
+ 0 - 6
prov.yaml


+ 4 - 0
server/api/api.go

@@ -37,6 +37,7 @@ type AppConfig struct {
 	Repository *repository.Repository
 	Repository *repository.Repository
 	ServerConf config.ServerConf
 	ServerConf config.ServerConf
 	RedisConf  *config.RedisConf
 	RedisConf  *config.RedisConf
+	DBConf     config.DBConf
 
 
 	// TestAgents if API is in testing mode
 	// TestAgents if API is in testing mode
 	TestAgents *TestAgents
 	TestAgents *TestAgents
@@ -63,6 +64,9 @@ type App struct {
 	// redis client for redis connection
 	// redis client for redis connection
 	RedisConf *config.RedisConf
 	RedisConf *config.RedisConf
 
 
+	// config for db
+	DBConf config.DBConf
+
 	// oauth-specific clients
 	// oauth-specific clients
 	GithubConf *oauth2.Config
 	GithubConf *oauth2.Config
 
 

+ 14 - 1
server/api/provision_handler.go

@@ -33,7 +33,12 @@ func (app *App) HandleProvisionTest(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 
 
-	_, err = agent.ProvisionTest(uint(projID), provisioner.Apply)
+	_, err = agent.ProvisionTest(
+		uint(projID),
+		provisioner.Apply,
+		&app.DBConf,
+		app.RedisConf,
+	)
 
 
 	if err != nil {
 	if err != nil {
 		app.handleErrorInternal(err, w)
 		app.handleErrorInternal(err, w)
@@ -111,6 +116,8 @@ func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Reques
 		form.ECRName,
 		form.ECRName,
 		infra,
 		infra,
 		provisioner.Apply,
 		provisioner.Apply,
+		&app.DBConf,
+		app.RedisConf,
 	)
 	)
 
 
 	if err != nil {
 	if err != nil {
@@ -199,6 +206,8 @@ func (app *App) HandleDestroyAWSECRInfra(w http.ResponseWriter, r *http.Request)
 		form.ECRName,
 		form.ECRName,
 		infra,
 		infra,
 		provisioner.Destroy,
 		provisioner.Destroy,
+		&app.DBConf,
+		app.RedisConf,
 	)
 	)
 
 
 	if err != nil {
 	if err != nil {
@@ -279,6 +288,8 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 		form.EKSName,
 		form.EKSName,
 		infra,
 		infra,
 		provisioner.Apply,
 		provisioner.Apply,
+		&app.DBConf,
+		app.RedisConf,
 	)
 	)
 
 
 	if err != nil {
 	if err != nil {
@@ -367,6 +378,8 @@ func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request)
 		form.EKSName,
 		form.EKSName,
 		infra,
 		infra,
 		provisioner.Destroy,
 		provisioner.Destroy,
+		&app.DBConf,
+		app.RedisConf,
 	)
 	)
 
 
 	if err != nil {
 	if err != nil {

Некоторые файлы не были показаны из-за большого количества измененных файлов