-
Notifications
You must be signed in to change notification settings - Fork 702
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Misc todo cleanup in fluxv2 plugin (#3030)
* step 1 * step 2 * step 3 * step 4 * Update cmd/kubeapps-apis/plugins/fluxv2/packages/v1alpha1/server.go Co-authored-by: Michael Nelson <absoludity@gmail.com> * step 5 * step 6 Co-authored-by: Michael Nelson <absoludity@gmail.com>
- Loading branch information
1 parent
0240c96
commit 4547597
Showing
11 changed files
with
671 additions
and
365 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
cmd/kubeapps-apis/plugins/fluxv2/packages/v1alpha1/conditions.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
Copyright © 2021 VMware | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/watch" | ||
log "k8s.io/klog/v2" | ||
) | ||
|
||
func isRepoReady(obj map[string]interface{}) (bool, error) { | ||
// see docs at https://fluxcd.io/docs/components/source/helmrepositories/ | ||
// Confirm the state we are observing is for the current generation | ||
observedGeneration, found, err := unstructured.NestedInt64(obj, "status", "observedGeneration") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
generation, found, err := unstructured.NestedInt64(obj, "metadata", "generation") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
if generation != observedGeneration { | ||
return false, nil | ||
} | ||
|
||
conditions, found, err := unstructured.NestedSlice(obj, "status", "conditions") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
|
||
for _, conditionUnstructured := range conditions { | ||
if conditionAsMap, ok := conditionUnstructured.(map[string]interface{}); ok { | ||
if typeString, ok := conditionAsMap["type"]; ok && typeString == "Ready" { | ||
if statusString, ok := conditionAsMap["status"]; ok { | ||
if statusString == "True" { | ||
// note that the current doc on https://fluxcd.io/docs/components/source/helmrepositories/ | ||
// incorrectly states the example status reason as "IndexationSucceeded". | ||
// The actual string is "IndexationSucceed" | ||
if reasonString, ok := conditionAsMap["reason"]; !ok || reasonString != "IndexationSucceed" { | ||
// should not happen | ||
log.Infof("Unexpected status of HelmRepository: %v", obj) | ||
} | ||
return true, nil | ||
} else if statusString == "False" { | ||
var msg string | ||
if msg, ok = conditionAsMap["message"].(string); !ok { | ||
msg = fmt.Sprintf("No message available in condition: %v", conditionAsMap) | ||
} | ||
return false, status.Errorf(codes.Internal, msg) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return false, nil | ||
} | ||
|
||
// the goal of this fn is to answer whether or not to stop waiting for chart reconciliation | ||
// which is different from answering whether the chart was pulled successfully | ||
// TODO (gfichtenholt): As above, hopefully this fn isn't required if we can only list charts that we know are ready. | ||
func isChartPullComplete(unstructuredChart *unstructured.Unstructured) (bool, error) { | ||
// see docs at https://fluxcd.io/docs/components/source/helmcharts/ | ||
// Confirm the state we are observing is for the current generation | ||
observedGeneration, found, err := unstructured.NestedInt64(unstructuredChart.Object, "status", "observedGeneration") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
generation, found, err := unstructured.NestedInt64(unstructuredChart.Object, "metadata", "generation") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
if generation != observedGeneration { | ||
return false, nil | ||
} | ||
|
||
conditions, found, err := unstructured.NestedSlice(unstructuredChart.Object, "status", "conditions") | ||
if err != nil { | ||
return false, err | ||
} else if !found { | ||
return false, nil | ||
} | ||
|
||
// check if ready=True | ||
for _, conditionUnstructured := range conditions { | ||
if conditionAsMap, ok := conditionUnstructured.(map[string]interface{}); ok { | ||
if typeString, ok := conditionAsMap["type"]; ok && typeString == "Ready" { | ||
if statusString, ok := conditionAsMap["status"]; ok { | ||
if statusString == "True" { | ||
if reasonString, ok := conditionAsMap["reason"]; !ok || reasonString != "ChartPullSucceeded" { | ||
// should not happen | ||
log.Infof("unexpected status of HelmChart: %v", *unstructuredChart) | ||
} | ||
return true, nil | ||
} else if statusString == "False" { | ||
var msg string | ||
if msg, ok = conditionAsMap["message"].(string); !ok { | ||
msg = fmt.Sprintf("No message available in condition: %v", conditionAsMap) | ||
} | ||
// chart pull is done and it's a failure | ||
return true, status.Errorf(codes.Internal, msg) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return false, nil | ||
} | ||
|
||
// TODO (gfichtenholt): | ||
// see https://github.com/kubeapps/kubeapps/pull/2915 for context | ||
// In the future you might instead want to consider something like | ||
// passing a results channel (of string urls) to pullChartTarball, so it returns | ||
// immediately and you wait on the results channel at the call-site, which would mean | ||
// you could call it for 20 different charts and just wait for the results to come in | ||
// whatever order they happen to take, rather than serially. | ||
func waitUntilChartPullComplete(watcher watch.Interface) (*string, error) { | ||
ch := watcher.ResultChan() | ||
// LISTEN TO CHANNEL | ||
for { | ||
event := <-ch | ||
if event.Type == watch.Modified { | ||
unstructuredChart, ok := event.Object.(*unstructured.Unstructured) | ||
if !ok { | ||
return nil, status.Errorf(codes.Internal, "Could not cast to unstructured.Unstructured") | ||
} | ||
|
||
done, err := isChartPullComplete(unstructuredChart) | ||
if err != nil { | ||
return nil, err | ||
} else if done { | ||
url, found, err := unstructured.NestedString(unstructuredChart.Object, "status", "url") | ||
if err != nil || !found { | ||
return nil, status.Errorf(codes.Internal, "expected field status.url not found on HelmChart: %v:\n%v", err, unstructuredChart) | ||
} | ||
return &url, nil | ||
} | ||
} else { | ||
// TODO handle other kinds of events | ||
return nil, status.Errorf(codes.Internal, "got unexpected event: %v", event) | ||
} | ||
} | ||
} |
Oops, something went wrong.