Skip to content

Commit 2b98d5d

Browse files
committed
HMS-5913: add package dates from RHEL lifecycle
Adds package streams info to package_sources. Pulls package stream info from the roadmap API and adds it to package sources if the RPM name matches. Also adds RHEL EoL as the end date for any package source that is not in the roadmap API. Uses the end date for the latest released version of the matching RHEL major version.
1 parent b502037 commit 2b98d5d

File tree

11 files changed

+480
-33
lines changed

11 files changed

+480
-33
lines changed

configs/config.yaml.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ clients:
134134
rbac: 1m
135135
pulp_content_path: 1h
136136
subscription_check: 1h
137+
roadmap: 24h
137138
feature_service:
138139
server: #https://feature.stage.api.redhat.com/features/v1
139140
client_cert:

pkg/cache/cache.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ type Cache interface {
2828

2929
GetRoadmapAppstreams(ctx context.Context) ([]byte, error)
3030
SetRoadmapAppstreams(ctx context.Context, roadmapAppstreamsResponse []byte)
31+
32+
GetRoadmapRhelLifecycle(ctx context.Context) ([]byte, error)
33+
SetRoadmapRhelLifecycle(ctx context.Context, rhelLifecyleResponse []byte)
3134
}
3235

3336
func Initialize() Cache {

pkg/cache/cache_mock.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cache/noop.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,12 @@ func (c *noOpCache) GetRoadmapAppstreams(ctx context.Context) ([]byte, error) {
6464
// SetRoadmapAppstreams a NoOp version to store cached roadmap appstreams check
6565
func (c *noOpCache) SetRoadmapAppstreams(ctx context.Context, response []byte) {
6666
}
67+
68+
// GetRoadmapRhelLifecycle a NoOp version to fetch a cached roadmap rhel lifecycle check
69+
func (c *noOpCache) GetRoadmapRhelLifecycle(ctx context.Context) ([]byte, error) {
70+
return nil, NotFound
71+
}
72+
73+
// SetRoadmapRhelLifecycle a NoOp version to store cached roadmap rhel lifecycle check
74+
func (c *noOpCache) SetRoadmapRhelLifecycle(ctx context.Context, response []byte) {
75+
}

pkg/cache/redis.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ func roadmapAppstreamsKey(ctx context.Context) string {
6161
return fmt.Sprintf("roadmap-appstreams:%v", identity.Identity.OrgID)
6262
}
6363

64+
func roadmapRhelLifecycleKey(ctx context.Context) string {
65+
identity := identity.GetIdentity(ctx)
66+
return fmt.Sprintf("roadmap-rhel-lifecycle:%v", identity.Identity.OrgID)
67+
}
68+
6469
// GetAccessList uses the request context to read user information, and then tries to retrieve the role AccessList from the cache
6570
func (c *redisCache) GetAccessList(ctx context.Context) (rbac.AccessList, error) {
6671
accessList := rbac.AccessList{}
@@ -184,7 +189,21 @@ func (c *redisCache) GetRoadmapAppstreams(ctx context.Context) ([]byte, error) {
184189

185190
func (c *redisCache) SetRoadmapAppstreams(ctx context.Context, response []byte) {
186191
key := roadmapAppstreamsKey(ctx)
187-
c.client.Set(ctx, key, string(response), config.Get().Clients.Redis.Expiration.SubscriptionCheck)
192+
c.client.Set(ctx, key, string(response), config.Get().Clients.Redis.Expiration.Roadmap)
193+
}
194+
195+
func (c *redisCache) GetRoadmapRhelLifecycle(ctx context.Context) ([]byte, error) {
196+
key := roadmapRhelLifecycleKey(ctx)
197+
buf, err := c.get(ctx, key)
198+
if err != nil {
199+
return nil, fmt.Errorf("redis get error: %w", err)
200+
}
201+
return buf, nil
202+
}
203+
204+
func (c *redisCache) SetRoadmapRhelLifecycle(ctx context.Context, response []byte) {
205+
key := roadmapRhelLifecycleKey(ctx)
206+
c.client.Set(ctx, key, string(response), config.Get().Clients.Redis.Expiration.Roadmap)
188207
}
189208

190209
func (c *redisCache) get(ctx context.Context, key string) ([]byte, error) {

pkg/clients/roadmap_client/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313

1414
type RoadmapClient interface {
1515
GetAppstreams(ctx context.Context) (AppstreamsResponse, int, error)
16+
GetRhelLifecycle(ctx context.Context) (LifecycleResponse, int, error)
17+
GetRhelLifecycleForLatestMajorVersions(ctx context.Context) (map[int]LifecycleEntity, error)
1618
}
1719

1820
type roadmapClient struct {

pkg/clients/roadmap_client/roadmap.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ type AppstreamEntity struct {
3535
Impl string `json:"impl"`
3636
}
3737

38+
type LifecycleResponse struct {
39+
Data []LifecycleEntity `json:"data"`
40+
}
41+
42+
type LifecycleEntity struct {
43+
Name string `json:"name"`
44+
StartDate string `json:"start_date"`
45+
EndDate string `json:"end_date"`
46+
Major int `json:"major"`
47+
Minor int `json:"minor"`
48+
}
49+
3850
func encodedIdentity(ctx context.Context) (string, error) {
3951
id := identity.GetIdentity(ctx)
4052
jsonIdentity, err := json.Marshal(id)
@@ -107,3 +119,82 @@ func (rc roadmapClient) GetAppstreams(ctx context.Context) (AppstreamsResponse,
107119

108120
return appStreamResp, statusCode, nil
109121
}
122+
123+
func (rc roadmapClient) GetRhelLifecycle(ctx context.Context) (LifecycleResponse, int, error) {
124+
statusCode := http.StatusInternalServerError
125+
server := config.Get().Clients.Roadmap.Server
126+
var err error
127+
var lifecycleResponse LifecycleResponse
128+
var body []byte
129+
130+
appstreams, err := rc.cache.GetRoadmapRhelLifecycle(ctx)
131+
if err != nil && !errors.Is(err, cache.NotFound) {
132+
log.Error().Err(err).Msg("GetAppstreams - error reading from cache")
133+
}
134+
if appstreams != nil {
135+
err = json.Unmarshal(appstreams, &lifecycleResponse)
136+
if err != nil {
137+
return LifecycleResponse{}, statusCode, fmt.Errorf("error during unmarshal response body: %w", err)
138+
}
139+
return lifecycleResponse, http.StatusOK, nil
140+
}
141+
142+
fullPath := server + "/lifecycle/rhel"
143+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fullPath, nil)
144+
if err != nil {
145+
return LifecycleResponse{}, statusCode, fmt.Errorf("error building request: %w", err)
146+
}
147+
148+
if config.Get().Clients.Roadmap.Username != "" && config.Get().Clients.Roadmap.Password != "" {
149+
req.SetBasicAuth(config.Get().Clients.Roadmap.Username, config.Get().Clients.Roadmap.Password)
150+
}
151+
152+
encodedXRHID, err := encodedIdentity(ctx)
153+
if err != nil {
154+
return LifecycleResponse{}, statusCode, fmt.Errorf("error getting encoded XRHID: %w", err)
155+
}
156+
req.Header.Set(api.IdentityHeader, encodedXRHID)
157+
158+
resp, err := rc.client.Do(req)
159+
if resp != nil {
160+
defer resp.Body.Close()
161+
162+
body, err = io.ReadAll(resp.Body)
163+
if err != nil {
164+
return LifecycleResponse{}, statusCode, fmt.Errorf("error reading response body: %w", err)
165+
}
166+
if resp.StatusCode != 0 {
167+
statusCode = resp.StatusCode
168+
}
169+
}
170+
if err != nil {
171+
return LifecycleResponse{}, statusCode, fmt.Errorf("error sending request: %w", err)
172+
}
173+
if statusCode < 200 || statusCode >= 300 {
174+
return LifecycleResponse{}, statusCode, fmt.Errorf("unexpected status code with body: %s", string(body))
175+
}
176+
177+
rc.cache.SetRoadmapRhelLifecycle(ctx, body)
178+
179+
err = json.Unmarshal(body, &lifecycleResponse)
180+
if err != nil {
181+
return LifecycleResponse{}, statusCode, fmt.Errorf("error during unmarshal response body: %w", err)
182+
}
183+
184+
return lifecycleResponse, statusCode, nil
185+
}
186+
187+
func (rc roadmapClient) GetRhelLifecycleForLatestMajorVersions(ctx context.Context) (map[int]LifecycleEntity, error) {
188+
lifecycleResp, _, err := rc.GetRhelLifecycle(ctx)
189+
if err != nil {
190+
return nil, err
191+
}
192+
193+
rhelEolMap := make(map[int]LifecycleEntity)
194+
for _, item := range lifecycleResp.Data {
195+
if existing, found := rhelEolMap[item.Major]; !found || (item.Minor > existing.Minor) {
196+
rhelEolMap[item.Major] = item
197+
}
198+
}
199+
return rhelEolMap, nil
200+
}

pkg/clients/roadmap_client/roadmap_client_mock.go

Lines changed: 65 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ type Expiration struct {
184184
Rbac time.Duration `mapstructure:"rbac"`
185185
PulpContentPath time.Duration `mapstructure:"pulp_content_path"`
186186
SubscriptionCheck time.Duration `mapstructure:"subscription_check"`
187+
Roadmap time.Duration `mapstructure:"roadmap"`
187188
}
188189

189190
type Sentry struct {
@@ -323,6 +324,7 @@ func setDefaults(v *viper.Viper) {
323324
v.SetDefault("clients.redis.expiration.rbac", 1*time.Minute)
324325
v.SetDefault("clients.redis.expiration.pulp_content_path", 1*time.Hour)
325326
v.SetDefault("clients.redis.expiration.subscription_check", 1*time.Hour)
327+
v.SetDefault("clients.redis.expiration.roadmap", 24*time.Hour)
326328

327329
v.SetDefault("clients.feature_service.server", "")
328330
v.SetDefault("clients.feature_service.client_cert", "")

0 commit comments

Comments
 (0)