diff --git a/api/database/sqlite/db.go b/api/database/sqlite/db.go index 7b89b4650..d8591d51a 100644 --- a/api/database/sqlite/db.go +++ b/api/database/sqlite/db.go @@ -163,7 +163,113 @@ func (connection *DbConnection) getEncryptionKey() []byte { } func (connection *DbConnection) Init() error { - connection.DB.AutoMigrate(&models.Version{}) - connection.DB.AutoMigrate(&portainer.Settings{}) + err := connection.DB.AutoMigrate(&models.Version{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Version") + } + err = connection.DB.AutoMigrate(&portainer.Settings{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Settings") + } + err = connection.DB.AutoMigrate(&portainer.APIKey{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate APIKey") + } + err = connection.DB.AutoMigrate(&portainer.User{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate User") + } + err = connection.DB.AutoMigrate(&portainer.CustomTemplate{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate CustomTemplate") + } + err = connection.DB.AutoMigrate(&portainer.DockerHub{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate DockerHub") + } + err = connection.DB.AutoMigrate(&portainer.EdgeGroup{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate EdgeGroup") + } + err = connection.DB.AutoMigrate(&portainer.EdgeJob{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate EdgeJob") + } + err = connection.DB.AutoMigrate(&portainer.EdgeStack{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate EdgeStack") + } + err = connection.DB.AutoMigrate(&portainer.Endpoint{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Endpoint") + } + err = connection.DB.AutoMigrate(&portainer.EndpointGroup{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate EndpointGroup") + } + err = connection.DB.AutoMigrate(&portainer.EndpointRelation{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate EndpointRelation") + } + err = connection.DB.AutoMigrate(&portainer.Extension{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Extension") + } + err = connection.DB.AutoMigrate(&portainer.FDOProfile{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate FDOProfile") + } + err = connection.DB.AutoMigrate(&portainer.HelmUserRepository{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate HelmUserRepository") + } + err = connection.DB.AutoMigrate(&portainer.Registry{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Registry") + } + err = connection.DB.AutoMigrate(&portainer.ResourceControl{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate ResourceControl") + } + err = connection.DB.AutoMigrate(&portainer.Role{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Role") + } + err = connection.DB.AutoMigrate(&portainer.Schedule{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Schedule") + } + err = connection.DB.AutoMigrate(&portainer.Snapshot{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Snapshot") + } + err = connection.DB.AutoMigrate(&portainer.SSLSettings{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate SSLSettings") + } + err = connection.DB.AutoMigrate(&portainer.Stack{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Stack") + } + err = connection.DB.AutoMigrate(&portainer.Tag{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Tag") + } + err = connection.DB.AutoMigrate(&portainer.Team{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Team") + } + err = connection.DB.AutoMigrate(&portainer.TeamMembership{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate TeamMembership") + } + err = connection.DB.AutoMigrate(&portainer.TunnelServerInfo{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate TunnelServerInfo") + } + err = connection.DB.AutoMigrate(&portainer.Webhook{}) + if err != nil { + log.Err(err).Msgf("failed to auto migrate Webhook") + } return nil } diff --git a/api/internal/authorization/access_control.go b/api/internal/authorization/access_control.go index 543fecb51..aebb4c484 100644 --- a/api/internal/authorization/access_control.go +++ b/api/internal/authorization/access_control.go @@ -127,7 +127,7 @@ func DecorateCustomTemplates(templates []portainer.CustomTemplate, resourceContr resourceControl := GetResourceControlByResourceIDAndType(strconv.Itoa(int(template.ID)), portainer.CustomTemplateResourceControl, resourceControls) if resourceControl != nil { - templates[idx].ResourceControl = resourceControl + templates[idx].ResourceControlID = resourceControl.ID } } @@ -152,7 +152,7 @@ func FilterAuthorizedCustomTemplates(customTemplates []portainer.CustomTemplate, authorizedTemplates := make([]portainer.CustomTemplate, 0) for _, customTemplate := range customTemplates { - if customTemplate.CreatedByUserID == user.ID || (customTemplate.ResourceControl != nil && UserCanAccessResource(user.ID, userTeamIDs, customTemplate.ResourceControl)) { + if customTemplate.CreatedByUserID == user.ID || (customTemplate.ResourceControlID == 0 && UserCanAccessResource(user.ID, userTeamIDs, customTemplate.ResourceControl)) { authorizedTemplates = append(authorizedTemplates, customTemplate) } } diff --git a/api/portainer.go b/api/portainer.go index 51464893c..a8e16f685 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -102,7 +102,7 @@ type ( FDOProfileID int FDOProfile struct { - ID FDOProfileID `json:"id"` + ID FDOProfileID `json:"id" gorm:"unique,primaryKey,autoIncrement"` Name string `json:"name"` FilePath string `json:"filePath"` NumberDevices int `json:"numberDevices"` @@ -159,7 +159,7 @@ type ( // CustomTemplate represents a custom template CustomTemplate struct { // CustomTemplate Identifier - ID CustomTemplateID `json:"Id" example:"1"` + ID CustomTemplateID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Title of the template Title string `json:"Title" example:"Nginx"` // Description of the template @@ -181,10 +181,10 @@ type ( // * 1 - swarm // * 2 - compose // * 3 - kubernetes - Type StackType `json:"Type" example:"1" enums:"1,2,3"` - ResourceControl *ResourceControl `json:"ResourceControl"` - Variables []CustomTemplateVariableDefinition - GitConfig *gittypes.RepoConfig `json:"GitConfig"` + Type StackType `json:"Type" example:"1"` + ResourceControlID ResourceControlID `json:"ResourceControl" gorm:"foreignKey"` + Variables []CustomTemplateVariableDefinition `json:"Variables" gorm:"serialize:json"` + GitConfig *gittypes.RepoConfig `json:"GitConfig" gorm:"serialize:json"` // IsComposeFormat indicates if the Kubernetes template is created from a Docker Compose file IsComposeFormat bool `example:"false"` } @@ -247,11 +247,11 @@ type ( // EdgeGroup represents an Edge group EdgeGroup struct { // EdgeGroup Identifier - ID EdgeGroupID `json:"Id" example:"1"` + ID EdgeGroupID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Name string `json:"Name"` Dynamic bool `json:"Dynamic"` - TagIDs []TagID `json:"TagIds"` - Endpoints []EndpointID `json:"Endpoints"` + TagIDs []TagID `json:"TagIds" gorm:"serializable:json"` + Endpoints []EndpointID `json:"Endpoints" gorm:"serializable:json"` PartialMatch bool `json:"PartialMatch"` } @@ -261,11 +261,11 @@ type ( // EdgeJob represents a job that can run on Edge environments(endpoints). EdgeJob struct { // EdgeJob Identifier - ID EdgeJobID `json:"Id" example:"1"` + ID EdgeJobID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Created int64 `json:"Created"` CronExpression string `json:"CronExpression"` - Endpoints map[EndpointID]EdgeJobEndpointMeta `json:"Endpoints"` - EdgeGroups []EdgeGroupID `json:"EdgeGroups"` + Endpoints map[EndpointID]EdgeJobEndpointMeta `json:"Endpoints" gorm:"serializable:json"` + EdgeGroups []EdgeGroupID `json:"EdgeGroups" gorm:"serializable:json"` Name string `json:"Name"` ScriptPath string `json:"ScriptPath"` Recurring bool `json:"Recurring"` @@ -292,21 +292,21 @@ type ( // Deprecated: in favor of EdgeJob EdgeSchedule struct { // EdgeSchedule Identifier - ID ScheduleID `json:"Id" example:"1"` + ID ScheduleID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` CronExpression string `json:"CronExpression"` Script string `json:"Script"` Version int `json:"Version"` - Endpoints []EndpointID `json:"Endpoints"` + Endpoints []EndpointID `json:"Endpoints" gorm:"serealize:json"` } //EdgeStack represents an edge stack EdgeStack struct { // EdgeStack Identifier - ID EdgeStackID `json:"Id" example:"1"` + ID EdgeStackID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Name string `json:"Name"` - Status map[EndpointID]EdgeStackStatus `json:"Status"` + Status map[EndpointID]EdgeStackStatus `json:"Status" gorm:"serealize:json"` CreationDate int64 `json:"CreationDate"` - EdgeGroups []EdgeGroupID `json:"EdgeGroups"` + EdgeGroups []EdgeGroupID `json:"EdgeGroups" gorm:"serealize:json"` ProjectPath string `json:"ProjectPath"` EntryPoint string `json:"EntryPoint"` Version int `json:"Version"` @@ -352,7 +352,7 @@ type ( // to connect to it Endpoint struct { // Environment(Endpoint) Identifier - ID EndpointID `json:"Id" example:"1"` + ID EndpointID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Environment(Endpoint) name Name string `json:"Name" example:"my-environment"` // Environment(Endpoint) environment(endpoint) type. 1 for a Docker environment(endpoint), 2 for an agent on Docker environment(endpoint) or 3 for an Azure environment(endpoint). @@ -363,19 +363,19 @@ type ( GroupID EndpointGroupID `json:"GroupId" example:"1"` // URL or IP address where exposed containers will be reachable PublicURL string `json:"PublicURL" example:"docker.mydomain.tld:2375"` - Gpus []Pair `json:"Gpus"` - TLSConfig TLSConfiguration `json:"TLSConfig"` - AzureCredentials AzureCredentials `json:"AzureCredentials,omitempty"` + Gpus []Pair `json:"Gpus" gorm:"serializable:json"` + TLSConfig TLSConfiguration `json:"TLSConfig" gorm:"serializable:json"` + AzureCredentials AzureCredentials `json:"AzureCredentials,omitempty" gorm:"serializable:json"` // List of tag identifiers to which this environment(endpoint) is associated - TagIDs []TagID `json:"TagIds"` + TagIDs []TagID `json:"TagIds" gorm:"serializable:json"` // The status of the environment(endpoint) (1 - up, 2 - down) Status EndpointStatus `json:"Status" example:"1"` // List of snapshots - Snapshots []DockerSnapshot `json:"Snapshots"` + Snapshots []DockerSnapshot `json:"Snapshots" gorm:"serializable:json"` // List of user identifiers authorized to connect to this environment(endpoint) - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` + UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies" gorm:"serializable:json"` // List of team identifiers authorized to connect to this environment(endpoint) - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` + TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies" gorm:"serializable:json"` // The identifier of the edge agent associated with this environment(endpoint) EdgeID string `json:"EdgeID,omitempty"` // The key which is used to map the agent to Portainer @@ -383,11 +383,11 @@ type ( // The check in interval for edge agent (in seconds) EdgeCheckinInterval int `json:"EdgeCheckinInterval" example:"5"` // Associated Kubernetes data - Kubernetes KubernetesData `json:"Kubernetes"` + Kubernetes KubernetesData `json:"Kubernetes" gorm:"serializable:json"` // Maximum version of docker-compose ComposeSyntaxMaxVersion string `json:"ComposeSyntaxMaxVersion" example:"3.8"` // Environment(Endpoint) specific security settings - SecuritySettings EndpointSecuritySettings + SecuritySettings EndpointSecuritySettings `gorm:"serializable:json"` // The identifier of the AMT Device associated with this environment(endpoint) AMTDeviceGUID string `json:"AMTDeviceGUID,omitempty" example:"4c4c4544-004b-3910-8037-b6c04f504633"` // LastCheckInDate mark last check-in date on checkin @@ -401,13 +401,13 @@ type ( UserTrusted bool // Whether we need to run any "post init migrations". - PostInitMigrations EndpointPostInitMigrations `json:"PostInitMigrations"` + PostInitMigrations EndpointPostInitMigrations `json:"PostInitMigrations" gorm:"serializable:json"` - Edge EnvironmentEdgeSettings + Edge EnvironmentEdgeSettings `gorm:"serializable:json"` Agent struct { Version string `example:"1.0.0"` - } + } `json:"Agent" gorm:"serializable:json"` EnableGPUManagement bool `json:"EnableGPUManagement"` @@ -419,11 +419,11 @@ type ( TLSKeyPath string `json:"TLSKey,omitempty"` // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` + AuthorizedUsers []UserID `json:"AuthorizedUsers" gorm:"serializable:json"` + AuthorizedTeams []TeamID `json:"AuthorizedTeams" gorm:"serializable:json"` // Deprecated in DBVersion == 22 - Tags []string `json:"Tags"` + Tags []string `json:"Tags" gorm:"serializable:json"` // Deprecated v2.18 IsEdgeDevice bool @@ -446,25 +446,25 @@ type ( // EndpointGroup represents a group of environments(endpoints) EndpointGroup struct { // Environment(Endpoint) group Identifier - ID EndpointGroupID `json:"Id" example:"1"` + ID EndpointGroupID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Environment(Endpoint) group name Name string `json:"Name" example:"my-environment-group"` // Description associated to the environment(endpoint) group Description string `json:"Description" example:"Environment(Endpoint) group description"` - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` + UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies" gorm:"serializable:json"` + TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies" gorm:"serializable:json"` // List of tags associated to this environment(endpoint) group - TagIDs []TagID `json:"TagIds"` + TagIDs []TagID `json:"TagIds" gorm:"serializable:json"` // Deprecated fields - Labels []Pair `json:"Labels"` + Labels []Pair `json:"Labels" gorm:"serializable:json"` // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` + AuthorizedUsers []UserID `json:"AuthorizedUsers" gorm:"serializable:json"` + AuthorizedTeams []TeamID `json:"AuthorizedTeams" gorm:"serializable:json"` // Deprecated in DBVersion == 22 - Tags []string `json:"Tags"` + Tags []string `json:"Tags" gorm:"serializable:json"` } // EndpointGroupID represents an environment(endpoint) group identifier @@ -520,7 +520,7 @@ type ( // Extension represents a deprecated Portainer extension Extension struct { // Extension Identifier - ID ExtensionID `json:"Id" example:"1"` + ID ExtensionID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Enabled bool `json:"Enabled"` Name string `json:"Name,omitempty"` ShortDescription string `json:"ShortDescription,omitempty"` @@ -530,11 +530,11 @@ type ( PriceDescription string `json:"PriceDescription,omitempty"` Deal bool `json:"Deal,omitempty"` Available bool `json:"Available,omitempty"` - License LicenseInformation `json:"License,omitempty"` + License LicenseInformation `json:"License,omitempty" gorm:"serializable:json"` Version string `json:"Version"` UpdateAvailable bool `json:"UpdateAvailable"` ShopURL string `json:"ShopURL,omitempty"` - Images []string `json:"Images,omitempty"` + Images []string `json:"Images,omitempty" gorm:"serializable:json"` Logo string `json:"Logo,omitempty"` } @@ -553,7 +553,7 @@ type ( // HelmUserRepositories stores a Helm repository URL for the given user HelmUserRepository struct { // Membership Identifier - ID HelmUserRepositoryID `json:"Id" example:"1"` + ID HelmUserRepositoryID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // User identifier UserID UserID `json:"UserId" example:"1"` // Helm repository URL @@ -740,7 +740,7 @@ type ( // to connect to it Registry struct { // Registry Identifier - ID RegistryID `json:"Id" example:"1"` + ID RegistryID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Registry Type (1 - Quay, 2 - Azure, 3 - Custom, 4 - Gitlab, 5 - ProGet, 6 - DockerHub, 7 - ECR) Type RegistryType `json:"Type" enums:"1,2,3,4,5,6,7"` // Registry Name @@ -755,22 +755,22 @@ type ( Username string `json:"Username" example:"registry user"` // Password or SecretAccessKey used to authenticate against this registry Password string `json:"Password,omitempty" example:"registry_password"` - ManagementConfiguration *RegistryManagementConfiguration `json:"ManagementConfiguration"` - Gitlab GitlabRegistryData `json:"Gitlab"` - Quay QuayRegistryData `json:"Quay"` - Ecr EcrData `json:"Ecr"` - RegistryAccesses RegistryAccesses `json:"RegistryAccesses"` + ManagementConfiguration *RegistryManagementConfiguration `json:"ManagementConfiguration" gorm:"serializable:json"` + Gitlab GitlabRegistryData `json:"Gitlab" gorm:"serializable:json"` + Quay QuayRegistryData `json:"Quay" gorm:"serializable:json"` + Ecr EcrData `json:"Ecr" gorm:"serializable:json"` + RegistryAccesses RegistryAccesses `json:"RegistryAccesses" gorm:"serializable:json"` // Deprecated fields // Deprecated in DBVersion == 31 - UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"` + UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies" gorm:"serializable:json"` // Deprecated in DBVersion == 31 - TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"` + TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies" gorm:"serializable:json"` // Deprecated in DBVersion == 18 - AuthorizedUsers []UserID `json:"AuthorizedUsers"` + AuthorizedUsers []UserID `json:"AuthorizedUsers" gorm:"serializable:json"` // Deprecated in DBVersion == 18 - AuthorizedTeams []TeamID `json:"AuthorizedTeams"` + AuthorizedTeams []TeamID `json:"AuthorizedTeams" gorm:"serializable:json"` // Stores temporary access token AccessToken string `json:"AccessToken,omitempty"` @@ -810,17 +810,17 @@ type ( // ResourceControl represent a reference to a Docker resource with specific access controls ResourceControl struct { // ResourceControl Identifier - ID ResourceControlID `json:"Id" example:"1"` + ID ResourceControlID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Docker resource identifier on which access control will be applied.\ // In the case of a resource control applied to a stack, use the stack name as identifier ResourceID string `json:"ResourceId" example:"617c5f22bb9b023d6daab7cba43a57576f83492867bc767d1c59416b065e5f08"` // List of Docker resources that will inherit this access control - SubResourceIDs []string `json:"SubResourceIds" example:"617c5f22bb9b023d6daab7cba43a57576f83492867bc767d1c59416b065e5f08"` + SubResourceIDs []string `json:"SubResourceIds" example:"617c5f22bb9b023d6daab7cba43a57576f83492867bc767d1c59416b065e5f08" gorm:"serializable:json"` // Type of Docker resource. Valid values are: 1- container, 2 -service // 3 - volume, 4 - secret, 5 - stack, 6 - config or 7 - custom template Type ResourceControlType `json:"Type" example:"1"` - UserAccesses []UserResourceAccess `json:"UserAccesses"` - TeamAccesses []TeamResourceAccess `json:"TeamAccesses"` + UserAccesses []UserResourceAccess `json:"UserAccesses" gorm:"serializable:json"` + TeamAccesses []TeamResourceAccess `json:"TeamAccesses" gorm:"serializable:json"` // Permit access to the associated resource to any user Public bool `json:"Public" example:"true"` // Permit access to resource only to admins @@ -843,13 +843,13 @@ type ( // to a team. Role struct { // Role Identifier - ID RoleID `json:"Id" example:"1"` + ID RoleID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Role name Name string `json:"Name" example:"HelpDesk"` // Role description Description string `json:"Description" example:"Read-only access of all resources in an environment(endpoint)"` // Authorizations associated to a role - Authorizations Authorizations `json:"Authorizations"` + Authorizations Authorizations `json:"Authorizations" gorm:"serializable:json"` Priority int `json:"Priority"` } @@ -861,13 +861,13 @@ type ( // APIKey represents an API key APIKey struct { - ID APIKeyID `json:"id" example:"1"` - UserID UserID `json:"userId" example:"1"` + ID APIKeyID `json:"id" example:"1" gorm:"unique,primaryKey,autoIncrement"` + UserID UserID `json:"userId" example:"1" gorm:"index,foreignKey=ID"` Description string `json:"description" example:"portainer-api-key"` - Prefix string `json:"prefix"` // API key identifier (7 char prefix) - DateCreated int64 `json:"dateCreated"` // Unix timestamp (UTC) when the API key was created - LastUsed int64 `json:"lastUsed"` // Unix timestamp (UTC) when the API key was last used - Digest []byte `json:"digest,omitempty"` // Digest represents SHA256 hash of the raw API key + Prefix string `json:"prefix"` // API key identifier (7 char prefix) + DateCreated int64 `json:"dateCreated"` // Unix timestamp (UTC) when the API key was created + LastUsed int64 `json:"lastUsed"` // Unix timestamp (UTC) when the API key was last used + Digest []byte `json:"digest,omitempty" gorm:"serializable:json"` // Digest represents SHA256 hash of the raw API key } // Schedule represents a scheduled job. @@ -877,13 +877,13 @@ type ( // Deprecated in favor of EdgeJob Schedule struct { // Schedule Identifier - ID ScheduleID `json:"Id" example:"1"` + ID ScheduleID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Name string CronExpression string Recurring bool Created int64 JobType JobType - EdgeSchedule *EdgeSchedule + EdgeSchedule *EdgeSchedule `json:"EdgeSchedule,omitempty" gorm:"foreignKey:ScheduleID"` } // ScheduleID represents a schedule identifier. @@ -989,7 +989,7 @@ type ( // Stack represents a Docker stack created via docker stack deploy Stack struct { // Stack Identifier - ID StackID `json:"Id" example:"1"` + ID StackID `json:"Id" gorm:"unique,primaryKey,autoIncrement" example:"1"` // Stack name Name string `json:"Name" example:"myStack"` // Stack type. 1 for a Swarm stack, 2 for a Compose stack @@ -1003,7 +1003,7 @@ type ( // A list of environment(endpoint) variables used during stack deployment Env []Pair `json:"Env"` // - ResourceControl *ResourceControl `json:"ResourceControl"` + ResourceControl *ResourceControl `json:"ResourceControl" gorm:"serializer:json"` // Stack status (1 - active, 2 - inactive) Status StackStatus `json:"Status" example:"1"` // Path on disk to the repository hosting the Stack file @@ -1019,11 +1019,11 @@ type ( // Only applies when deploying stack with multiple files AdditionalFiles []string `json:"AdditionalFiles"` // The auto update settings of a git stack - AutoUpdate *AutoUpdateSettings `json:"AutoUpdate"` + AutoUpdate *AutoUpdateSettings `json:"AutoUpdate" gorm:"serializer:json"` // The stack deployment option - Option *StackOption `json:"Option"` + Option *StackOption `json:"Option" gorm:"serializer:json"` // The git config of this stack - GitConfig *gittypes.RepoConfig + GitConfig *gittypes.RepoConfig `json:"GitConfig" gorm:"serializer:json"` // Whether the stack is from a app template FromAppTemplate bool `example:"false"` // Kubernetes namespace if stack is a kube application @@ -1058,13 +1058,13 @@ type ( // Tag represents a tag that can be associated to a resource Tag struct { // Tag identifier - ID TagID `example:"1"` + ID TagID `example:"1" gorm:"unique,primaryKey,autoIncrement"` // Tag name Name string `json:"Name" example:"org/acme"` // A set of environment(endpoint) ids that have this tag - Endpoints map[EndpointID]bool `json:"Endpoints"` + Endpoints map[EndpointID]bool `json:"Endpoints" gorm:"serializer:json"` // A set of environment(endpoint) group ids that have this tag - EndpointGroups map[EndpointGroupID]bool `json:"EndpointGroups"` + EndpointGroups map[EndpointGroupID]bool `json:"EndpointGroups" gorm:"serializer:json"` } // TagID represents a tag identifier @@ -1073,7 +1073,7 @@ type ( // Team represents a list of user accounts Team struct { // Team Identifier - ID TeamID `json:"Id" example:"1"` + ID TeamID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Team name Name string `json:"Name" example:"developers"` } @@ -1087,7 +1087,7 @@ type ( // TeamMembership represents a membership association between a user and a team TeamMembership struct { // Membership Identifier - ID TeamMembershipID `json:"Id" example:"1"` + ID TeamMembershipID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // User identifier UserID UserID `json:"UserID" example:"1"` // Team identifier @@ -1102,7 +1102,7 @@ type ( // TeamResourceAccess represents the level of control on a resource for a specific team TeamResourceAccess struct { TeamID TeamID `json:"TeamId"` - AccessLevel ResourceAccessLevel `json:"AccessLevel"` + AccessLevel ResourceAccessLevel `json:"AccessLevel" gorm:"serializer:json"` } // Template represents an application template that can be used as an App Template @@ -1110,7 +1110,7 @@ type ( Template struct { // Mandatory container/stack fields // Template Identifier - ID TemplateID `json:"Id" example:"1"` + ID TemplateID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` // Template type. Valid values are: 1 (container), 2 (Swarm stack) or 3 (Compose stack) Type TemplateType `json:"type" example:"1"` // Title of the template @@ -1125,7 +1125,7 @@ type ( Image string `json:"image" example:"nginx:latest"` // Mandatory stack fields - Repository TemplateRepository `json:"repository"` + Repository TemplateRepository `json:"repository" gorm:"serializer:json"` // Mandatory Edge stack fields // Stack file used for this template @@ -1137,14 +1137,14 @@ type ( // URL of the template's logo Logo string `json:"logo,omitempty" example:"https://portainer.io/img/logo.svg"` // A list of environment(endpoint) variables used during the template deployment - Env []TemplateEnv `json:"env,omitempty"` + Env []TemplateEnv `json:"env,omitempty" gorm:"serializer:json"` // A note that will be displayed in the UI. Supports HTML content Note string `json:"note,omitempty" example:"This is my custom template"` // Platform associated to the template. // Valid values are: 'linux', 'windows' or leave empty for multi-platform Platform string `json:"platform,omitempty" example:"linux"` // A list of categories associated to the template - Categories []string `json:"categories,omitempty" example:"database"` + Categories []string `json:"categories,omitempty" example:"database" gorm:"serializer:json"` // Optional container fields // The URL of a registry associated to the image for a container template @@ -1154,11 +1154,11 @@ type ( // Name of a network that will be used on container deployment if it exists inside the environment(endpoint) Network string `json:"network,omitempty" example:"mynet"` // A list of volumes used during the container template deployment - Volumes []TemplateVolume `json:"volumes,omitempty"` + Volumes []TemplateVolume `json:"volumes,omitempty" gorm:"serializer:json"` // A list of ports exposed by the container - Ports []string `json:"ports,omitempty" example:"8080:80/tcp"` + Ports []string `json:"ports,omitempty" example:"8080:80/tcp" gorm:"serializer:json"` // Container labels - Labels []Pair `json:"labels,omitempty"` + Labels []Pair `json:"labels,omitempty" gorm:"serializer:json"` // Whether the container should be started in privileged mode Privileged bool `json:"privileged,omitempty" example:"true"` // Whether the container should be started in @@ -1183,7 +1183,7 @@ type ( // If set to true, will not generate any input for this variable in the UI Preset bool `json:"preset,omitempty" example:"false"` // A list of name/value that will be used to generate a dropdown in the UI - Select []TemplateEnvSelect `json:"select,omitempty"` + Select []TemplateEnvSelect `json:"select,omitempty" gorm:"serializer:json"` } // TemplateEnvSelect represents text/value pair that will be displayed as a choice for the @@ -1264,22 +1264,22 @@ type ( // User represents a user account User struct { // User Identifier - ID UserID `json:"Id" example:"1"` + ID UserID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` Username string `json:"Username" example:"bob"` Password string `json:"Password,omitempty" swaggerignore:"true"` // User role (1 for administrator account and 2 for regular account) - Role UserRole `json:"Role" example:"1"` - TokenIssueAt int64 `json:"TokenIssueAt" example:"1"` - ThemeSettings UserThemeSettings + Role UserRole `json:"Role" example:"1"` + TokenIssueAt int64 `json:"TokenIssueAt" example:"1"` + ThemeSettings UserThemeSettings `gorm:"serializer:json"` // Deprecated fields // Deprecated UserTheme string `example:"dark"` // Deprecated in DBVersion == 25 - PortainerAuthorizations Authorizations + PortainerAuthorizations Authorizations `gorm:"serializer:json"` // Deprecated in DBVersion == 25 - EndpointAuthorizations EndpointAuthorizations + EndpointAuthorizations EndpointAuthorizations `gorm:"serializer:json"` } // UserAccessPolicies represent the association of an access policy and a user @@ -1291,7 +1291,7 @@ type ( // UserResourceAccess represents the level of control on a resource for a specific user UserResourceAccess struct { UserID UserID `json:"UserId"` - AccessLevel ResourceAccessLevel `json:"AccessLevel"` + AccessLevel ResourceAccessLevel `json:"AccessLevel" gorm:"serializer:json"` } // UserRole represents the role of a user. It can be either an administrator @@ -1307,12 +1307,11 @@ type ( // Webhook represents a url webhook that can be used to update a service Webhook struct { // Webhook Identifier - ID WebhookID `json:"Id" example:"1"` - Token string `json:"Token"` - ResourceID string `json:"ResourceId"` - EndpointID EndpointID `json:"EndpointId"` - RegistryID RegistryID `json:"RegistryId"` - // Type of webhook (1 - service) + ID WebhookID `json:"Id" example:"1" gorm:"unique,primaryKey,autoIncrement"` + Token string `json:"Token"` + ResourceID string `json:"ResourceId"` + EndpointID EndpointID `json:"EndpointId"` + RegistryID RegistryID `json:"RegistryId"` WebhookType WebhookType `json:"Type"` } @@ -1324,8 +1323,8 @@ type ( Snapshot struct { EndpointID EndpointID `json:"EndpointId"` - Docker *DockerSnapshot `json:"Docker"` - Kubernetes *KubernetesSnapshot `json:"Kubernetes"` + Docker *DockerSnapshot `json:"Docker" gorm:"serializer:json"` + Kubernetes *KubernetesSnapshot `json:"Kubernetes" gorm:"serializer:json"` } // CLIService represents a service for managing CLI