github.com/sacloud/libsacloud/v2@v2.32.3/helper/service/containerregistry/builder.go (about) 1 // Copyright 2016-2022 The Libsacloud Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package containerregistry 16 17 import ( 18 "context" 19 "errors" 20 21 "github.com/sacloud/libsacloud/v2/sacloud" 22 "github.com/sacloud/libsacloud/v2/sacloud/types" 23 ) 24 25 // Builder コンテナレジストリのビルダー 26 type Builder struct { 27 ID types.ID 28 29 Name string 30 Description string 31 Tags types.Tags 32 IconID types.ID 33 AccessLevel types.EContainerRegistryAccessLevel 34 VirtualDomain string 35 SubDomainLabel string 36 Users []*User 37 SettingsHash string 38 Client sacloud.ContainerRegistryAPI 39 } 40 41 // User represents API parameter/response structure 42 type User struct { 43 UserName string 44 Password string 45 Permission types.EContainerRegistryPermission 46 } 47 48 func (b *Builder) Build(ctx context.Context) (*sacloud.ContainerRegistry, error) { 49 if b.ID.IsEmpty() { 50 return b.create(ctx) 51 } 52 return b.update(ctx) 53 } 54 55 func (b *Builder) create(ctx context.Context) (*sacloud.ContainerRegistry, error) { 56 created, err := b.Client.Create(ctx, &sacloud.ContainerRegistryCreateRequest{ 57 Name: b.Name, 58 Description: b.Description, 59 Tags: b.Tags, 60 IconID: b.IconID, 61 AccessLevel: b.AccessLevel, 62 VirtualDomain: b.VirtualDomain, 63 SubDomainLabel: b.SubDomainLabel, 64 }) 65 if err != nil { 66 return nil, err 67 } 68 69 if len(b.Users) == 0 { 70 return created, nil 71 } 72 return created, b.reconcileUsers(ctx, created.ID) 73 } 74 75 func (b *Builder) update(ctx context.Context) (*sacloud.ContainerRegistry, error) { 76 current, err := b.Client.Read(ctx, b.ID) 77 if err != nil { 78 return nil, err 79 } 80 if current.SubDomainLabel != b.SubDomainLabel { 81 return nil, errors.New("SubDomainLabel cannot be changed") 82 } 83 84 updated, err := b.Client.Update(ctx, b.ID, &sacloud.ContainerRegistryUpdateRequest{ 85 Name: b.Name, 86 Description: b.Description, 87 Tags: b.Tags, 88 IconID: b.IconID, 89 AccessLevel: b.AccessLevel, 90 VirtualDomain: b.VirtualDomain, 91 SettingsHash: b.SettingsHash, 92 }) 93 if err != nil { 94 return nil, err 95 } 96 return updated, b.reconcileUsers(ctx, updated.ID) 97 } 98 99 func (b *Builder) reconcileUsers(ctx context.Context, id types.ID) error { 100 currentUsers, err := b.Client.ListUsers(ctx, id) 101 if err != nil { 102 return err 103 } 104 105 if currentUsers != nil { 106 // delete 107 for _, username := range b.deletedUsers(currentUsers.Users) { 108 if err := b.Client.DeleteUser(ctx, id, username); err != nil { 109 return err 110 } 111 } 112 // update 113 for _, user := range b.updatedUsers(currentUsers.Users) { 114 if err := b.Client.UpdateUser(ctx, id, user.UserName, &sacloud.ContainerRegistryUserUpdateRequest{ 115 Password: user.Password, // Note: パスワードが空(Update時など)もあるが、nakedでomitemptyがついてるため問題なし 116 Permission: user.Permission, 117 }); err != nil { 118 return err 119 } 120 } 121 } 122 123 // create 124 var users []*sacloud.ContainerRegistryUser 125 if currentUsers != nil { 126 users = currentUsers.Users 127 } 128 for _, user := range b.createdUsers(users) { 129 if err := b.Client.AddUser(ctx, id, &sacloud.ContainerRegistryUserCreateRequest{ 130 UserName: user.UserName, 131 Password: user.Password, 132 Permission: user.Permission, 133 }); err != nil { 134 return err 135 } 136 } 137 return nil 138 } 139 140 func (b *Builder) deletedUsers(currentUsers []*sacloud.ContainerRegistryUser) []string { 141 var results []string 142 for _, current := range currentUsers { 143 exists := false 144 for _, desired := range b.Users { 145 if current.UserName == desired.UserName { 146 exists = true 147 break 148 } 149 } 150 if !exists { 151 results = append(results, current.UserName) 152 } 153 } 154 return results 155 } 156 157 func (b *Builder) updatedUsers(currentUsers []*sacloud.ContainerRegistryUser) []*User { 158 var results []*User 159 for _, current := range currentUsers { 160 for _, desired := range b.Users { 161 if current.UserName == desired.UserName { 162 results = append(results, desired) 163 break 164 } 165 } 166 } 167 return results 168 } 169 170 func (b *Builder) createdUsers(currentUsers []*sacloud.ContainerRegistryUser) []*User { 171 var results []*User 172 for _, created := range b.Users { 173 exists := false 174 for _, current := range currentUsers { 175 if created.UserName == current.UserName { 176 exists = true 177 break 178 } 179 } 180 if !exists { 181 results = append(results, created) 182 } 183 } 184 return results 185 }