github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/container_owner.go (about) 1 package db 2 3 import ( 4 "fmt" 5 "time" 6 7 sq "github.com/Masterminds/squirrel" 8 "github.com/pf-qiu/concourse/v6/atc" 9 ) 10 11 //go:generate counterfeiter . ContainerOwner 12 13 // ContainerOwner designates the data the container should reference that 14 // identifies its lifecycle. When the owner goes away, the container should 15 // be garbage collected. 16 type ContainerOwner interface { 17 Find(conn Conn) (sq.Eq, bool, error) 18 Create(tx Tx, workerName string) (map[string]interface{}, error) 19 } 20 21 // NewImageCheckContainerOwner references a container whose image resource this 22 // container is checking. When the referenced container transitions to another 23 // state, or disappears, the container can be removed. 24 func NewImageCheckContainerOwner( 25 container CreatingContainer, 26 teamID int, 27 ) ContainerOwner { 28 return imageCheckContainerOwner{ 29 Container: container, 30 TeamID: teamID, 31 } 32 } 33 34 type imageCheckContainerOwner struct { 35 Container CreatingContainer 36 TeamID int 37 } 38 39 func (c imageCheckContainerOwner) Find(Conn) (sq.Eq, bool, error) { 40 return sq.Eq(c.sqlMap()), true, nil 41 } 42 43 func (c imageCheckContainerOwner) Create(Tx, string) (map[string]interface{}, error) { 44 return c.sqlMap(), nil 45 } 46 47 func (c imageCheckContainerOwner) sqlMap() map[string]interface{} { 48 return map[string]interface{}{ 49 "image_check_container_id": c.Container.ID(), 50 "team_id": c.TeamID, 51 } 52 } 53 54 // NewImageGetContainerOwner references a container whose image resource this 55 // container is fetching. When the referenced container transitions to another 56 // state, or disappears, the container can be removed. 57 func NewImageGetContainerOwner( 58 container CreatingContainer, 59 teamID int, 60 ) ContainerOwner { 61 return imageGetContainerOwner{ 62 Container: container, 63 TeamID: teamID, 64 } 65 } 66 67 type imageGetContainerOwner struct { 68 Container CreatingContainer 69 TeamID int 70 } 71 72 func (c imageGetContainerOwner) Find(Conn) (sq.Eq, bool, error) { 73 return sq.Eq(c.sqlMap()), true, nil 74 } 75 76 func (c imageGetContainerOwner) Create(Tx, string) (map[string]interface{}, error) { 77 return c.sqlMap(), nil 78 } 79 80 func (c imageGetContainerOwner) sqlMap() map[string]interface{} { 81 return map[string]interface{}{ 82 "image_get_container_id": c.Container.ID(), 83 "team_id": c.TeamID, 84 } 85 } 86 87 // NewBuildStepContainerOwner references a step within a build. When the build 88 // becomes non-interceptible or disappears, the container can be removed. 89 func NewBuildStepContainerOwner( 90 buildID int, 91 planID atc.PlanID, 92 teamID int, 93 ) ContainerOwner { 94 return buildStepContainerOwner{ 95 BuildID: buildID, 96 PlanID: planID, 97 TeamID: teamID, 98 } 99 } 100 101 type buildStepContainerOwner struct { 102 BuildID int 103 PlanID atc.PlanID 104 TeamID int 105 } 106 107 func (c buildStepContainerOwner) Find(Conn) (sq.Eq, bool, error) { 108 return sq.Eq(c.sqlMap()), true, nil 109 } 110 111 func (c buildStepContainerOwner) Create(Tx, string) (map[string]interface{}, error) { 112 return c.sqlMap(), nil 113 } 114 115 func (c buildStepContainerOwner) sqlMap() map[string]interface{} { 116 return map[string]interface{}{ 117 "build_id": c.BuildID, 118 "plan_id": c.PlanID, 119 "team_id": c.TeamID, 120 } 121 } 122 123 // NewResourceConfigCheckSessionContainerOwner references a resource config and 124 // worker base resource type, with an expiry. When the resource config or 125 // worker base resource type disappear, or the expiry is reached, the container 126 // can be removed. 127 func NewResourceConfigCheckSessionContainerOwner( 128 resourceConfigID int, 129 baseResourceTypeID int, 130 expiries ContainerOwnerExpiries, 131 ) ContainerOwner { 132 return resourceConfigCheckSessionContainerOwner{ 133 resourceConfigID: resourceConfigID, 134 baseResourceTypeID: baseResourceTypeID, 135 expiries: expiries, 136 } 137 } 138 139 type resourceConfigCheckSessionContainerOwner struct { 140 resourceConfigID int 141 baseResourceTypeID int 142 expiries ContainerOwnerExpiries 143 } 144 145 type ContainerOwnerExpiries struct { 146 Min time.Duration 147 Max time.Duration 148 } 149 150 func (c resourceConfigCheckSessionContainerOwner) Find(conn Conn) (sq.Eq, bool, error) { 151 var ids []int 152 rows, err := psql.Select("id"). 153 From("resource_config_check_sessions"). 154 Where(sq.And{ 155 sq.Eq{"resource_config_id": c.resourceConfigID}, 156 sq.Expr("expires_at > NOW()"), 157 }). 158 RunWith(conn). 159 Query() 160 if err != nil { 161 return nil, false, err 162 } 163 164 for rows.Next() { 165 var id int 166 err = rows.Scan(&id) 167 if err != nil { 168 return nil, false, err 169 } 170 171 ids = append(ids, id) 172 } 173 174 if len(ids) == 0 { 175 return nil, false, nil 176 } 177 178 return sq.Eq{ 179 "resource_config_check_session_id": ids, 180 }, true, nil 181 } 182 183 func (c resourceConfigCheckSessionContainerOwner) Create(tx Tx, workerName string) (map[string]interface{}, error) { 184 var wbrtID int 185 err := psql.Select("id"). 186 From("worker_base_resource_types"). 187 Where(sq.Eq{ 188 "worker_name": workerName, 189 "base_resource_type_id": c.baseResourceTypeID, 190 }). 191 Suffix("FOR SHARE"). 192 RunWith(tx). 193 QueryRow(). 194 Scan(&wbrtID) 195 if err != nil { 196 return nil, fmt.Errorf("get worker base resource type id: %s", err) 197 } 198 199 expiryStmt := fmt.Sprintf( 200 "NOW() + LEAST(GREATEST('%d seconds'::interval, NOW() - max(start_time)), '%d seconds'::interval)", 201 int(c.expiries.Min.Seconds()), 202 int(c.expiries.Max.Seconds()), 203 ) 204 205 var rccsID int 206 err = psql.Insert("resource_config_check_sessions"). 207 SetMap(map[string]interface{}{ 208 "resource_config_id": c.resourceConfigID, 209 "worker_base_resource_type_id": wbrtID, 210 "expires_at": sq.Expr("(SELECT " + expiryStmt + " FROM workers)"), 211 }). 212 Suffix(` 213 ON CONFLICT (resource_config_id, worker_base_resource_type_id) DO UPDATE SET 214 resource_config_id = ?, 215 worker_base_resource_type_id = ? 216 RETURNING id 217 `, c.resourceConfigID, wbrtID). 218 RunWith(tx). 219 QueryRow(). 220 Scan(&rccsID) 221 if err != nil { 222 return nil, fmt.Errorf("upsert resource config check session: %s", err) 223 } 224 225 return map[string]interface{}{ 226 "resource_config_check_session_id": rccsID, 227 }, nil 228 }