Quellcode durchsuchen

Merge branch 'master' into nafees/pr-env-comments

Mohammed Nafees vor 3 Jahren
Ursprung
Commit
50b01cace3

+ 37 - 0
api/server/handlers/infra/forms.go

@@ -500,6 +500,43 @@ tabs:
       placeholder: "ex: 10"
       settings:
         default: 10
+- name: iam
+  label: IAM
+  sections:
+  - name: toggle_aws_auth
+    contents:
+    - type: heading
+      label: Configure IAM Access
+    - type: checkbox
+      variable: manage_aws_auth_configmap
+      label: Allow Porter to manage AWS authentication for the cluster.
+      settings:
+        default: true
+  - name: aws_auth_warning
+    show_if: 
+      not: manage_aws_auth_configmap
+    contents:
+    - type: subtitle
+      label: "WARNING - turning this value off will result in the aws-auth configmap getting removed from the cluster, and will take existing AWS nodes offline until the configmap is re-added with the node's IAM role ARN. Make sure you know what you are doing."
+  - name: arns
+    show_if: manage_aws_auth_configmap
+    contents:
+    - type: heading
+      label: Users
+    - type: subtitle
+      label: "Add AWS users to the cluster. The left input should be a valid AWS user ARN, and the right side should be a group on the cluster. For example, arn:aws:iam::66666666666:user/user1: system:masters."
+    - type: key-value-array
+      variable: aws_auth_users
+      settings:
+        default: {}
+    - type: heading
+      label: Roles
+    - type: subtitle
+      label: "Add AWS roles to the cluster. The left input should be a valid AWS role ARN, and the right side should be a group on the cluster. For example, arn:aws:iam::66666666666:role/role1: system:masters."
+    - type: key-value-array
+      variable: aws_auth_roles
+      settings:
+        default: {}
 - name: advanced
   label: Advanced
   sections:

+ 2 - 0
api/types/infra.go

@@ -42,6 +42,8 @@ type Infra struct {
 	// The project that this integration belongs to
 	ProjectID uint `json:"project_id"`
 
+	Name string `json:"name"`
+
 	APIVersion    string `json:"api_version,omitempty"`
 	SourceLink    string `json:"source_link,omitempty"`
 	SourceVersion string `json:"source_version,omitempty"`

+ 9 - 6
api/types/stacks.go

@@ -71,6 +71,9 @@ type Stack struct {
 	// The display name of the stack
 	Name string `json:"name"`
 
+	// The namespace that the stack was deployed to
+	Namespace string `json:"namespace"`
+
 	// A unique id for the stack
 	ID string `json:"id"`
 
@@ -190,13 +193,13 @@ type StackSourceConfig struct {
 // swagger:model
 type CreateStackSourceConfigRequest struct {
 	// required: true
-	Name string `json:"name"`
+	Name string `json:"name" form:"required"`
 
 	// required: true
-	ImageRepoURI string `json:"image_repo_uri"`
+	ImageRepoURI string `json:"image_repo_uri" form:"required"`
 
 	// required: true
-	ImageTag string `json:"image_tag"`
+	ImageTag string `json:"image_tag" form:"required"`
 
 	// If this field is empty, the resource is deployed directly from the image repo uri
 	StackSourceConfigBuild *StackSourceConfigBuild `json:"build,omitempty"`
@@ -205,13 +208,13 @@ type CreateStackSourceConfigRequest struct {
 // swagger:model
 type UpdateStackSourceConfigRequest struct {
 	// required: true
-	Name string `json:"name"`
+	Name string `json:"name" form:"required"`
 
 	// required: true
-	ImageRepoURI string `json:"image_repo_uri"`
+	ImageRepoURI string `json:"image_repo_uri" form:"required"`
 
 	// required: true
-	ImageTag string `json:"image_tag"`
+	ImageTag string `json:"image_tag" form:"required"`
 }
 
 type StackSourceConfigBuild struct {

+ 26 - 7
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/ExpandedStack.tsx

@@ -17,6 +17,7 @@ import {
   InfoWrapper,
   LastDeployed,
   LineBreak,
+  NamespaceTag,
   SepDot,
   Text,
 } from "../components/styles";
@@ -79,13 +80,19 @@ const ExpandedStack = () => {
 
   return (
     <div>
-      <TitleSection
-        materialIconClass="material-icons-outlined"
-        icon={"lan"}
-        capitalize
-      >
-        {stack.name}
-      </TitleSection>
+      <StackTitleWrapper>
+        <TitleSection
+          materialIconClass="material-icons-outlined"
+          icon={"lan"}
+          capitalize
+        >
+          {stack.name}
+        </TitleSection>
+        <NamespaceTag.Wrapper>
+          Namespace
+          <NamespaceTag.Tag>{stack.namespace}</NamespaceTag.Tag>
+        </NamespaceTag.Wrapper>
+      </StackTitleWrapper>
       <RevisionList
         revisions={stack.revisions}
         currentRevision={currentRevision}
@@ -222,3 +229,15 @@ const StackErrorMessageStyles = {
     font-weight: bold;
   `,
 };
+
+const StackTitleWrapper = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+
+  // Hotfix to make sure the title section and the namespace tag are aligned
+  ${NamespaceTag.Wrapper} {
+    margin-bottom: 15px;
+  }
+`;

+ 4 - 1
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/_RevisionList.tsx

@@ -168,6 +168,8 @@ const _RevisionList = ({
 export default _RevisionList;
 
 const StyledRevisionSection = styled.div`
+  display: flex;
+  flex-direction: column;
   position: relative;
   width: 100%;
   max-height: ${(props: { showRevisions: boolean }) =>
@@ -195,7 +197,7 @@ const RevisionHeader = styled.div`
   display: flex;
   justify-content: space-between;
   align-items: center;
-  height: 40px;
+  min-height: 40px;
   font-size: 13px;
   width: 100%;
   padding-left: 15px;
@@ -228,6 +230,7 @@ const RevisionPreview = styled.div`
 
 const TableWrapper = styled.div`
   padding-bottom: 20px;
+  overflow-y: auto;
 `;
 
 const RevisionsTable = styled.table`

+ 11 - 5
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/components/Select.tsx

@@ -75,6 +75,16 @@ const Select = <T extends unknown>({
     );
   }
 
+  const isSelected = (option: T, value: T) => {
+    if (!value) {
+      return false;
+    }
+
+    if (isOptionEqualToValue) {
+      return isOptionEqualToValue(option, value);
+    }
+  };
+
   return (
     <div>
       {getLabel()}
@@ -107,11 +117,7 @@ const Select = <T extends unknown>({
                     key={i}
                     onClick={() => !readOnly && handleOptionClick(option)}
                     lastItem={i === options.length - 1}
-                    selected={
-                      isOptionEqualToValue
-                        ? isOptionEqualToValue(option, value)
-                        : option === value
-                    }
+                    selected={isSelected(option, value)}
                     height={dropdown?.option?.height}
                   >
                     {accessor(option)}

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/components/SourceEditorDocker.tsx

@@ -148,7 +148,7 @@ const _DockerRepositorySelector = ({
         accessor={(val) => val.name}
         label="Docker Registry"
         placeholder="Select a registry"
-        isOptionEqualToValue={(a, b) => a.url === b.url}
+        isOptionEqualToValue={(a, b) => a?.url === b?.url}
         readOnly={readOnly}
         isLoading={isLoading}
         dropdown={{

+ 25 - 9
dashboard/src/main/home/cluster-dashboard/stacks/_StackList.tsx

@@ -13,6 +13,7 @@ import {
   Flex,
   InfoWrapper,
   LastDeployed,
+  NamespaceTag,
   SepDot,
   Text,
 } from "./components/styles";
@@ -80,6 +81,10 @@ const StackList = ({ namespace }: { namespace: string }) => {
           setIsLoading(false);
         }
       });
+
+    return () => {
+      isSubscribed = false;
+    };
   }, [namespace]);
 
   if (isLoading) {
@@ -104,16 +109,22 @@ const StackList = ({ namespace }: { namespace: string }) => {
           <StackCard
             as={DynamicLink}
             key={stack?.id}
-            to={`/stacks/${namespace}/${stack?.id}`}
+            to={`/stacks/${stack?.namespace}/${stack?.id}`}
           >
             <DataContainer>
-              <StackName>
-                <StackIcon>
-                  <i className="material-icons-outlined">lan</i>
-                </StackIcon>
-                <span>{stack.name}</span>
-              </StackName>
-
+              <Top>
+                <StackName>
+                  <StackIcon>
+                    <i className="material-icons-outlined">lan</i>
+                  </StackIcon>
+                  <span>{stack.name}</span>
+                </StackName>
+                <SepDot>•</SepDot>
+                <NamespaceTag.Wrapper>
+                  Namespace
+                  <NamespaceTag.Tag>{stack.namespace}</NamespaceTag.Tag>
+                </NamespaceTag.Wrapper>
+              </Top>
               <InfoWrapper>
                 <LastDeployed>
                   <Status
@@ -200,7 +211,6 @@ const StackName = styled.div`
   display: flex;
   font-size: 14px;
   align-items: center;
-  margin-bottom: 10px;
 `;
 
 const DataContainer = styled.div`
@@ -215,3 +225,9 @@ const StackCard = styled(Card)`
   font-size: 13px;
   font-weight: 500;
 `;
+
+const Top = styled.div`
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+`;

+ 33 - 0
dashboard/src/main/home/cluster-dashboard/stacks/components/styles.ts

@@ -96,3 +96,36 @@ export const Flex = styled.div`
   display: flex;
   align-items: center;
 `;
+
+export const NamespaceTag = {
+  Wrapper: styled.div`
+    height: 20px;
+    font-size: 12px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #ffffff44;
+    border: 1px solid #ffffff44;
+    border-radius: 3px;
+    padding-left: 5px;
+  `,
+
+  Tag: styled.div`
+    height: 20px;
+    margin-left: 6px;
+    color: #aaaabb;
+    background: #ffffff22;
+    border-radius: 3px;
+    font-size: 12px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 0px 6px;
+    padding-left: 7px;
+    border-top-left-radius: 0px;
+    border-bottom-left-radius: 0px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  `,
+};

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/stacks/types.ts

@@ -31,6 +31,7 @@ export type Stack = {
   name: string;
   created_at: string;
   updated_at: string;
+  namespace: string;
 
   revisions: StackRevision[];
 

+ 4 - 4
dashboard/src/main/home/infrastructure/InfrastructureList.tsx

@@ -92,6 +92,10 @@ const InfrastructureList = () => {
           );
         },
       },
+      {
+        Header: "Name",
+        accessor: "name",
+      },
       {
         Header: "Status",
         accessor: "status",
@@ -131,10 +135,6 @@ const InfrastructureList = () => {
           return readableDate(row.original.updated_at);
         },
       },
-      {
-        Header: "Source",
-        accessor: "source_link",
-      },
       {
         Header: "Version",
         accessor: "source_version",

+ 1 - 0
dashboard/src/shared/types.tsx

@@ -426,6 +426,7 @@ export type OperationType =
 
 export type Infrastructure = {
   id: number;
+  name?: string;
   api_version: string;
   created_at: string;
   updated_at: string;

+ 37 - 0
internal/models/infra.go

@@ -125,10 +125,47 @@ func GetOperationID() (string, error) {
 	return encryption.GenerateRandomBytes(10)
 }
 
+type getInfraName struct {
+	Name        string `json:"name"`
+	ClusterName string `json:"cluster_name"`
+	DOCRName    string `json:"docr_name"`
+	ECRName     string `json:"ecr_name"`
+	ACRName     string `json:"acr_name"`
+}
+
 // ToInfraType generates an external Infra to be shared over REST
 func (i *Infra) ToInfraType() *types.Infra {
+	// perform best attempt to get infra name
+	var name string
+	infraName := &getInfraName{}
+
+	if err := json.Unmarshal(i.LastApplied, infraName); err == nil {
+		if infraName.DOCRName != "" {
+			name = infraName.DOCRName
+		}
+
+		if infraName.ECRName != "" {
+			name = infraName.ECRName
+		}
+
+		if infraName.ACRName != "" {
+			name = infraName.ACRName
+		}
+
+		if infraName.ClusterName != "" {
+			name = infraName.ClusterName
+		}
+
+		if infraName.Name != "" {
+			name = infraName.Name
+		}
+	} else if err != nil {
+		fmt.Println("ERRWAS", err)
+	}
+
 	return &types.Infra{
 		ID:               i.ID,
+		Name:             name,
 		CreatedAt:        i.CreatedAt,
 		UpdatedAt:        i.UpdatedAt,
 		ProjectID:        i.ProjectID,

+ 1 - 0
internal/models/stack.go

@@ -39,6 +39,7 @@ func (s *Stack) ToStackType() *types.Stack {
 		CreatedAt:      s.CreatedAt,
 		UpdatedAt:      s.UpdatedAt,
 		Name:           s.Name,
+		Namespace:      s.Namespace,
 		ID:             s.UID,
 		LatestRevision: latestRevision,
 		Revisions:      revisions,

+ 1 - 0
internal/repository/gorm/helpers_test.go

@@ -71,6 +71,7 @@ func setupTestEnv(tester *tester, t *testing.T) {
 		&models.ClusterCandidate{},
 		&models.ClusterResolver{},
 		&models.Infra{},
+		&models.Operation{},
 		&models.GitActionConfig{},
 		&models.Invite{},
 		&models.KubeEvent{},

+ 32 - 0
internal/repository/gorm/infra.go

@@ -91,8 +91,40 @@ func (repo *InfraRepository) ListInfrasByProjectID(
 		return nil, err
 	}
 
+	infraIDs := make([]uint, 0)
+
 	for _, infra := range infras {
 		repo.DecryptInfraData(infra, repo.key)
+		infraIDs = append(infraIDs, infra.ID)
+	}
+
+	// get the latest operation for each infra and use it to set LastApplied
+	operations := make([]*models.Operation, 0)
+
+	if err := repo.db.Where("operations.infra_id IN (?)", infraIDs).Where(`
+	operations.id IN (
+	  SELECT o2.id FROM (SELECT MAX(operations.id) id FROM operations WHERE operations.infra_id IN (?) GROUP BY operations.infra_id) o2
+	)
+  `, infraIDs).Find(&operations).Error; err != nil {
+		return nil, err
+	}
+
+	// insert operations into a map
+	infraIDToOperationMap := make(map[uint]models.Operation)
+
+	for _, op := range operations {
+		err := repo.DecryptOperationData(op, repo.key)
+
+		if err == nil {
+			infraIDToOperationMap[op.InfraID] = *op
+		}
+	}
+
+	// look up each revision for each stack
+	for _, infra := range infras {
+		if _, exists := infraIDToOperationMap[infra.ID]; exists {
+			infra.LastApplied = infraIDToOperationMap[infra.ID].LastApplied
+		}
 	}
 
 	return infras, nil

+ 16 - 0
internal/repository/gorm/stack.go

@@ -74,6 +74,22 @@ func (repo *StackRepository) ListStacks(projectID, clusterID uint, namespace str
 	return stacks, nil
 }
 
+func (repo *StackRepository) ReadStackByID(projectID, stackID uint) (*models.Stack, error) {
+	stack := &models.Stack{}
+
+	if err := repo.db.
+		Preload("Revisions", func(db *gorm.DB) *gorm.DB {
+			return db.Order("stack_revisions.revision_number DESC").Limit(100)
+		}).
+		Preload("Revisions.Resources").
+		Preload("Revisions.SourceConfigs").
+		Where("stacks.project_id = ? AND stacks.id = ?", projectID, stackID).First(&stack).Error; err != nil {
+		return nil, err
+	}
+
+	return stack, nil
+}
+
 // ReadStack gets a stack specified by its string id
 func (repo *StackRepository) ReadStackByStringID(projectID uint, stackID string) (*models.Stack, error) {
 	stack := &models.Stack{}

+ 1 - 0
internal/repository/stack.go

@@ -5,6 +5,7 @@ import "github.com/porter-dev/porter/internal/models"
 // StackRepository represents the set of queries on the Stack model
 type StackRepository interface {
 	CreateStack(stack *models.Stack) (*models.Stack, error)
+	ReadStackByID(projectID, stackID uint) (*models.Stack, error)
 	ReadStackByStringID(projectID uint, stackID string) (*models.Stack, error)
 	ListStacks(projectID uint, clusterID uint, namespace string) ([]*models.Stack, error)
 	DeleteStack(stack *models.Stack) (*models.Stack, error)

+ 4 - 0
internal/repository/test/stack.go

@@ -21,6 +21,10 @@ func (repo *StackRepository) ListStacks(projectID, clusterID uint, namespace str
 	panic("unimplemented")
 }
 
+func (repo *StackRepository) ReadStackByID(projectID, stackID uint) (*models.Stack, error) {
+	panic("unimplemented")
+}
+
 // ReadStack gets a stack specified by its string id
 func (repo *StackRepository) ReadStackByStringID(projectID uint, stackID string) (*models.Stack, error) {
 	panic("unimplemented")

+ 18 - 2
internal/stacks/hooks.go

@@ -1,6 +1,8 @@
 package stacks
 
 import (
+	"fmt"
+
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"gorm.io/gorm"
 	"helm.sh/helm/v3/pkg/release"
@@ -24,13 +26,27 @@ func UpdateHelmRevision(config *config.Config, projID, clusterID uint, rel *rele
 		return err
 	}
 
-	// read the revision number and create a new revision of the stack
-	stackRevision, err := config.Repo.Stack().ReadStackRevision(stackResource.StackRevisionID)
+	// read the revision number corresponding and create a new revision of the stack
+	oldStackRevision, err := config.Repo.Stack().ReadStackRevision(stackResource.StackRevisionID)
 
 	if err != nil {
 		return err
 	}
 
+	// get the latest revision for that stack
+	stack, err := config.Repo.Stack().ReadStackByID(projID, oldStackRevision.StackID)
+
+	if err != nil {
+		return err
+	}
+
+	if len(stack.Revisions) == 0 {
+		return fmt.Errorf("length of stack revision list was 0")
+	}
+
+	currStackRevision := stack.Revisions[0]
+	stackRevision := &currStackRevision
+
 	clonedSourceConfigs, err := CloneSourceConfigs(stackRevision.SourceConfigs)
 
 	if err != nil {