소스 검색

Merge pull request #2141 from porter-dev/nafees/hotfixes

[POR-542] Read in the Github app secret at launch time
abelanger5 3 년 전
부모
커밋
f3cb138679

+ 2 - 2
api/server/handlers/environment/create.go

@@ -174,11 +174,11 @@ func getGithubClientFromEnvironment(config *config.Config, env *models.Environme
 	}
 
 	// authenticate as github app installation
-	itr, err := ghinstallation.NewKeyFromFile(
+	itr, err := ghinstallation.New(
 		http.DefaultTransport,
 		int64(ghAppId),
 		int64(env.GitInstallationID),
-		config.ServerConf.GithubAppSecretPath,
+		config.ServerConf.GithubAppSecret,
 	)
 
 	if err != nil {

+ 50 - 34
api/server/handlers/environment/list_deployments_by_cluster.go

@@ -71,6 +71,8 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 			deployments = append(deployments, deployment)
 		}
 
+		envToGithubClientMap := make(map[uint]*github.Client)
+
 		var wg sync.WaitGroup
 		wg.Add(len(deployments))
 
@@ -82,10 +84,21 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 				return
 			}
 
+			if _, ok := envToGithubClientMap[env.ID]; !ok {
+				client, err := getGithubClientFromEnvironment(c.Config(), env)
+
+				if err != nil {
+					c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+					return
+				}
+
+				envToGithubClientMap[env.ID] = client
+			}
+
 			go func(depl *types.Deployment) {
 				defer wg.Done()
 
-				updateDeploymentWithGithubWorkflowRunStatus(c.Config(), env, depl)
+				updateDeploymentWithGithubWorkflowRunStatus(c.Config(), envToGithubClientMap[env.ID], env, depl)
 			}(deployment)
 		}
 
@@ -99,7 +112,18 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 		}
 
 		for _, env := range envList {
-			prs, err := fetchOpenPullRequests(r.Context(), c.Config(), env, deplInfoMap)
+			if _, ok := envToGithubClientMap[env.ID]; !ok {
+				client, err := getGithubClientFromEnvironment(c.Config(), env)
+
+				if err != nil {
+					c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+					return
+				}
+
+				envToGithubClientMap[env.ID] = client
+			}
+
+			prs, err := fetchOpenPullRequests(r.Context(), c.Config(), envToGithubClientMap[env.ID], env, deplInfoMap)
 
 			if err != nil {
 				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
@@ -125,6 +149,13 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 
 		deplInfoMap := make(map[string]bool)
 
+		client, err := getGithubClientFromEnvironment(c.Config(), env)
+
+		if err != nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			return
+		}
+
 		for _, depl := range depls {
 			deployment := depl.ToDeploymentType()
 			deplInfoMap[fmt.Sprintf(
@@ -140,23 +171,16 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 		wg.Add(len(deployments))
 
 		for _, deployment := range deployments {
-			env, err := c.Repo().Environment().ReadEnvironmentByID(project.ID, cluster.ID, deployment.EnvironmentID)
-
-			if err != nil {
-				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-				return
-			}
-
 			go func(depl *types.Deployment) {
 				defer wg.Done()
 
-				updateDeploymentWithGithubWorkflowRunStatus(c.Config(), env, depl)
+				updateDeploymentWithGithubWorkflowRunStatus(c.Config(), client, env, depl)
 			}(deployment)
 		}
 
 		wg.Wait()
 
-		prs, err := fetchOpenPullRequests(r.Context(), c.Config(), env, deplInfoMap)
+		prs, err := fetchOpenPullRequests(r.Context(), c.Config(), client, env, deplInfoMap)
 
 		if err != nil {
 			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
@@ -174,6 +198,7 @@ func (c *ListDeploymentsByClusterHandler) ServeHTTP(w http.ResponseWriter, r *ht
 
 func updateDeploymentWithGithubWorkflowRunStatus(
 	config *config.Config,
+	client *github.Client,
 	env *models.Environment,
 	deployment *types.Deployment,
 ) {
@@ -181,25 +206,21 @@ func updateDeploymentWithGithubWorkflowRunStatus(
 		return
 	}
 
-	client, err := getGithubClientFromEnvironment(config, env)
+	latestWorkflowRun, err := commonutils.GetLatestWorkflowRun(client, env.GitRepoOwner, env.GitRepoName,
+		fmt.Sprintf("porter_%s_env.yml", env.Name), deployment.PRBranchFrom)
 
 	if err == nil {
-		latestWorkflowRun, err := commonutils.GetLatestWorkflowRun(client, env.GitRepoOwner, env.GitRepoName,
-			fmt.Sprintf("porter_%s_env.yml", env.Name), deployment.PRBranchFrom)
-
-		if err == nil {
-			deployment.LastWorkflowRunURL = latestWorkflowRun.GetHTMLURL()
-
-			if (latestWorkflowRun.GetStatus() == "in_progress" ||
-				latestWorkflowRun.GetStatus() == "queued") &&
-				deployment.Status != types.DeploymentStatusCreating {
-				deployment.Status = types.DeploymentStatusUpdating
-			} else if latestWorkflowRun.GetStatus() == "completed" {
-				if latestWorkflowRun.GetConclusion() == "failure" {
-					deployment.Status = types.DeploymentStatusFailed
-				} else if latestWorkflowRun.GetConclusion() == "timed_out" {
-					deployment.Status = types.DeploymentStatusTimedOut
-				}
+		deployment.LastWorkflowRunURL = latestWorkflowRun.GetHTMLURL()
+
+		if (latestWorkflowRun.GetStatus() == "in_progress" ||
+			latestWorkflowRun.GetStatus() == "queued") &&
+			deployment.Status != types.DeploymentStatusCreating {
+			deployment.Status = types.DeploymentStatusUpdating
+		} else if latestWorkflowRun.GetStatus() == "completed" {
+			if latestWorkflowRun.GetConclusion() == "failure" {
+				deployment.Status = types.DeploymentStatusFailed
+			} else if latestWorkflowRun.GetConclusion() == "timed_out" {
+				deployment.Status = types.DeploymentStatusTimedOut
 			}
 		}
 	}
@@ -208,15 +229,10 @@ func updateDeploymentWithGithubWorkflowRunStatus(
 func fetchOpenPullRequests(
 	ctx context.Context,
 	config *config.Config,
+	client *github.Client,
 	env *models.Environment,
 	deplInfoMap map[string]bool,
 ) ([]*types.PullRequest, error) {
-	client, err := getGithubClientFromEnvironment(config, env)
-
-	if err != nil {
-		return nil, err
-	}
-
 	openPRs, resp, err := client.PullRequests.List(ctx, env.GitRepoOwner, env.GitRepoName,
 		&github.PullRequestListOptions{
 			ListOptions: github.ListOptions{

+ 20 - 12
api/server/handlers/webhook/github_incoming.go

@@ -37,14 +37,15 @@ func NewGithubIncomingWebhookHandler(
 
 func (c *GithubIncomingWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	payload, err := github.ValidatePayload(r, []byte(c.Config().ServerConf.GithubIncomingWebhookSecret))
+
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error validating webhook payload: %w", err)))
 		return
 	}
 
 	event, err := github.ParseWebHook(github.WebHookType(r), payload)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error parsing webhook: %w", err)))
 		return
 	}
 
@@ -53,7 +54,7 @@ func (c *GithubIncomingWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.
 		err = c.processPullRequestEvent(event, r)
 
 		if err != nil {
-			c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error processing pull request webhook event: %w", err)))
 			return
 		}
 	}
@@ -73,14 +74,15 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 	env, err := c.Repo().Environment().ReadEnvironmentByWebhookIDOwnerRepoName(webhookID, owner, repo)
 
 	if err != nil {
-		return err
+		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s] error reading environment: %w", webhookID, owner, repo, err)
 	}
 
 	// create deployment on GitHub API
 	client, err := getGithubClientFromEnvironment(c.Config(), env)
 
 	if err != nil {
-		return err
+		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error getting github client: %w",
+			webhookID, owner, repo, env.ID, err)
 	}
 
 	if env.Mode == "auto" && event.GetAction() == "opened" {
@@ -98,7 +100,8 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 		)
 
 		if err != nil {
-			return err
+			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error creating workflow dispatch event: %w",
+				webhookID, owner, repo, env.ID, err)
 		}
 	} else if event.GetAction() == "synchronize" || event.GetAction() == "closed" {
 		depl, err := c.Repo().Environment().ReadDeploymentByGitDetails(
@@ -106,7 +109,8 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 		)
 
 		if err != nil {
-			return err
+			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error reading deployment: %w",
+				webhookID, owner, repo, env.ID, err)
 		}
 
 		if depl.Status != types.DeploymentStatusInactive {
@@ -125,13 +129,15 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 				)
 
 				if err != nil {
-					return err
+					return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error creating workflow dispatch event: %w",
+						webhookID, owner, repo, env.ID, depl.ID, err)
 				}
 			} else {
 				err = c.deleteDeployment(r, depl, env, client)
 
 				if err != nil {
-					return err
+					return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error deleting deployment: %w",
+						webhookID, owner, repo, env.ID, depl.ID, err)
 				}
 			}
 		}
@@ -149,7 +155,7 @@ func (c *GithubIncomingWebhookHandler) deleteDeployment(
 	cluster, err := c.Repo().Cluster().ReadCluster(env.ProjectID, env.ClusterID)
 
 	if err != nil {
-		return err
+		return fmt.Errorf("[projectID: %d, clusterID: %d] error reading cluster: %w", env.ProjectID, env.ClusterID, err)
 	}
 
 	agent, err := c.GetAgent(r, cluster, "")
@@ -163,7 +169,8 @@ func (c *GithubIncomingWebhookHandler) deleteDeployment(
 		err = agent.DeleteNamespace(depl.Namespace)
 
 		if err != nil {
-			return err
+			return fmt.Errorf("[owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error deleting namespace '%s': %w",
+				env.GitRepoOwner, env.GitRepoName, env.ID, depl.ID, depl.Namespace, err)
 		}
 	}
 
@@ -188,7 +195,8 @@ func (c *GithubIncomingWebhookHandler) deleteDeployment(
 	_, err = c.Repo().Environment().UpdateDeployment(depl)
 
 	if err != nil {
-		return err
+		return fmt.Errorf("[owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error updating deployment: %w",
+			env.GitRepoOwner, env.GitRepoName, env.ID, depl.ID, err)
 	}
 
 	return nil

+ 1 - 0
api/server/shared/config/env/envconfs.go

@@ -46,6 +46,7 @@ type ServerConf struct {
 	GithubAppWebhookSecret string `env:"GITHUB_APP_WEBHOOK_SECRET"`
 	GithubAppID            string `env:"GITHUB_APP_ID"`
 	GithubAppSecretPath    string `env:"GITHUB_APP_SECRET_PATH"`
+	GithubAppSecret        []byte
 
 	GoogleClientID         string `env:"GOOGLE_CLIENT_ID"`
 	GoogleClientSecret     string `env:"GOOGLE_CLIENT_SECRET"`

+ 9 - 0
api/server/shared/config/loader/loader.go

@@ -2,6 +2,7 @@ package loader
 
 import (
 	"fmt"
+	"io/ioutil"
 	"net/http"
 	"strconv"
 
@@ -167,6 +168,14 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 				BaseURL:      sc.ServerURL,
 			}, sc.GithubAppName, sc.GithubAppWebhookSecret, sc.GithubAppSecretPath, AppID)
 		}
+
+		secret, err := ioutil.ReadFile(sc.GithubAppSecretPath)
+
+		if err != nil {
+			return nil, fmt.Errorf("could not read github app secret: %s", err)
+		}
+
+		sc.GithubAppSecret = append(sc.GithubAppSecret, secret...)
 	}
 
 	if sc.SlackClientID != "" && sc.SlackClientSecret != "" {