Skip to content

Commit 2103d38

Browse files
authored
Merge pull request #33 from fluxcd/git-timeout
api: add timeout field to GitRepositorySpec
2 parents 4304bbe + 920d37f commit 2103d38

File tree

8 files changed

+93
-24
lines changed

8 files changed

+93
-24
lines changed

api/v1alpha1/gitrepository_types.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"time"
21+
2022
corev1 "k8s.io/api/core/v1"
2123
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2224
)
@@ -40,6 +42,11 @@ type GitRepositorySpec struct {
4042
// +required
4143
Interval metav1.Duration `json:"interval"`
4244

45+
// The timeout for remote git operations like cloning.
46+
// +kubebuilder:validation:Default=20s
47+
// +optional
48+
Timeout *metav1.Duration `json:"timeout,omitempty"`
49+
4350
// The git reference to checkout and monitor for changes, defaults to
4451
// master branch.
4552
// +optional
@@ -105,6 +112,10 @@ const (
105112
GitOperationFailedReason string = "GitOperationFailed"
106113
)
107114

115+
// GitRepositoryReady sets the given artifact and url on the
116+
// HelmRepository and resets the conditions to SourceCondition of
117+
// type Ready with status true and the given reason and message.
118+
// It returns the modified GitRepository.
108119
func GitRepositoryReady(repository GitRepository, artifact Artifact, url, reason, message string) GitRepository {
109120
repository.Status.Conditions = []SourceCondition{
110121
{
@@ -128,6 +139,9 @@ func GitRepositoryReady(repository GitRepository, artifact Artifact, url, reason
128139
return repository
129140
}
130141

142+
// GitRepositoryNotReady resets the conditions of the HelmRepository
143+
// to SourceCondition of type Ready with status false and the given
144+
// reason and message. It returns the modified GitRepository.
131145
func GitRepositoryNotReady(repository GitRepository, reason, message string) GitRepository {
132146
repository.Status.Conditions = []SourceCondition{
133147
{
@@ -141,15 +155,25 @@ func GitRepositoryNotReady(repository GitRepository, reason, message string) Git
141155
return repository
142156
}
143157

158+
// ReadyMessage returns the message of the SourceCondition
159+
// of type Ready with status true if present, or an empty string.
144160
func GitRepositoryReadyMessage(repository GitRepository) string {
145161
for _, condition := range repository.Status.Conditions {
146-
if condition.Type == ReadyCondition {
162+
if condition.Type == ReadyCondition && condition.Status == corev1.ConditionTrue {
147163
return condition.Message
148164
}
149165
}
150166
return ""
151167
}
152168

169+
// GetTimeout returns the configured timeout or the default.
170+
func (in *GitRepository) GetTimeout() time.Duration {
171+
if in.Spec.Timeout != nil {
172+
return in.Spec.Timeout.Duration
173+
}
174+
return time.Second * 20
175+
}
176+
153177
// GetArtifact returns the latest artifact from the source
154178
// if present in the status sub-resource.
155179
func (in *GitRepository) GetArtifact() *Artifact {

api/v1alpha1/helmchart_types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ const (
6666
ChartPullSucceededReason string = "ChartPullSucceeded"
6767
)
6868

69+
// HelmChartReady sets the given artifact and url on the HelmChart
70+
// and resets the conditions to SourceCondition of type Ready with
71+
// status true and the given reason and message. It returns the
72+
// modified HelmChart.
6973
func HelmChartReady(chart HelmChart, artifact Artifact, url, reason, message string) HelmChart {
7074
chart.Status.Conditions = []SourceCondition{
7175
{
@@ -89,6 +93,9 @@ func HelmChartReady(chart HelmChart, artifact Artifact, url, reason, message str
8993
return chart
9094
}
9195

96+
// HelmChartNotReady resets the conditions of the HelmChart to
97+
// SourceCondition of type Ready with status false and the given
98+
// reason and message. It returns the modified HelmChart.
9299
func HelmChartNotReady(chart HelmChart, reason, message string) HelmChart {
93100
chart.Status.Conditions = []SourceCondition{
94101
{
@@ -102,6 +109,8 @@ func HelmChartNotReady(chart HelmChart, reason, message string) HelmChart {
102109
return chart
103110
}
104111

112+
// HelmChartReadyMessage returns the message of the SourceCondition
113+
// of type Ready with status true if present, or an empty string.
105114
func HelmChartReadyMessage(chart HelmChart) string {
106115
for _, condition := range chart.Status.Conditions {
107116
if condition.Type == ReadyCondition && condition.Status == corev1.ConditionTrue {

api/v1alpha1/helmrepository_types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ const (
6565
IndexationSucceededReason string = "IndexationSucceed"
6666
)
6767

68+
// HelmRepositoryReady sets the given artifact and url on the
69+
// HelmRepository and resets the conditions to SourceCondition of
70+
// type Ready with status true and the given reason and message.
71+
// It returns the modified HelmRepository.
6872
func HelmRepositoryReady(repository HelmRepository, artifact Artifact, url, reason, message string) HelmRepository {
6973
repository.Status.Conditions = []SourceCondition{
7074
{
@@ -88,6 +92,9 @@ func HelmRepositoryReady(repository HelmRepository, artifact Artifact, url, reas
8892
return repository
8993
}
9094

95+
// HelmRepositoryNotReady resets the conditions of the HelmRepository
96+
// to SourceCondition of type Ready with status false and the given
97+
// reason and message. It returns the modified HelmRepository.
9198
func HelmRepositoryNotReady(repository HelmRepository, reason, message string) HelmRepository {
9299
repository.Status.Conditions = []SourceCondition{
93100
{
@@ -101,6 +108,8 @@ func HelmRepositoryNotReady(repository HelmRepository, reason, message string) H
101108
return repository
102109
}
103110

111+
// HelmRepositoryReadyMessage returns the message of the SourceCondition
112+
// of type Ready with status true if present, or an empty string.
104113
func HelmRepositoryReadyMessage(repository HelmRepository) string {
105114
for _, condition := range repository.Status.Conditions {
106115
if condition.Type == ReadyCondition && condition.Status == corev1.ConditionTrue {

api/v1alpha1/zz_generated.deepcopy.go

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

config/crd/bases/source.fluxcd.io_gitrepositories.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ spec:
8282
TODO: Add other useful fields. apiVersion, kind, uid?'
8383
type: string
8484
type: object
85+
timeout:
86+
description: The timeout for remote git operations like cloning.
87+
type: string
8588
url:
8689
description: The repository URL, can be a HTTP or SSH address.
8790
pattern: ^(http|https|ssh)://

controllers/gitrepository_controller.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"io/ioutil"
2323
"os"
24-
"time"
2524

2625
"github.com/blang/semver"
2726
"github.com/go-git/go-git/v5"
@@ -52,8 +51,7 @@ type GitRepositoryReconciler struct {
5251
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=gitrepositories/status,verbs=get;update;patch
5352

5453
func (r *GitRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
55-
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
56-
defer cancel()
54+
ctx := context.Background()
5755

5856
var repo sourcev1.GitRepository
5957
if err := r.Get(ctx, req.NamespacedName, &repo); err != nil {
@@ -174,7 +172,8 @@ func (r *GitRepositoryReconciler) sync(ctx context.Context, repository sourcev1.
174172
defer os.RemoveAll(tmpGit)
175173

176174
// clone to tmp
177-
repo, err := git.PlainClone(tmpGit, false, &git.CloneOptions{
175+
gitCtx, cancel := context.WithTimeout(ctx, repository.GetTimeout())
176+
repo, err := git.PlainCloneContext(gitCtx, tmpGit, false, &git.CloneOptions{
178177
URL: repository.Spec.URL,
179178
Auth: auth,
180179
RemoteName: "origin",
@@ -186,6 +185,7 @@ func (r *GitRepositoryReconciler) sync(ctx context.Context, repository sourcev1.
186185
Progress: nil,
187186
Tags: tagMode,
188187
})
188+
cancel()
189189
if err != nil {
190190
err = fmt.Errorf("git clone error: %w", err)
191191
return sourcev1.GitRepositoryNotReady(repository, sourcev1.GitOperationFailedReason, err.Error()), err
@@ -350,6 +350,8 @@ func (r *GitRepositoryReconciler) sync(ctx context.Context, repository sourcev1.
350350
return sourcev1.GitRepositoryReady(repository, artifact, url, sourcev1.GitOperationSucceedReason, message), nil
351351
}
352352

353+
// shouldResetStatus returns a boolean indicating if the status of the
354+
// given repository should be reset and a reset HelmChartStatus.
353355
func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepository) (bool, sourcev1.GitRepositoryStatus) {
354356
resetStatus := false
355357
if repository.Status.Artifact != nil {
@@ -374,6 +376,8 @@ func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepos
374376
}
375377
}
376378

379+
// gc performs a garbage collection on all but current artifacts of
380+
// the given repository.
377381
func (r *GitRepositoryReconciler) gc(repository sourcev1.GitRepository) error {
378382
if repository.Status.Artifact != nil {
379383
return r.Storage.RemoveAllButCurrent(*repository.Status.Artifact)

controllers/helmchart_controller.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"io/ioutil"
2323
"net/url"
24-
"time"
2524

2625
"github.com/go-logr/logr"
2726
"helm.sh/helm/v3/pkg/getter"
@@ -52,8 +51,7 @@ type HelmChartReconciler struct {
5251
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=helmcharts/status,verbs=get;update;patch
5352

5453
func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
55-
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
56-
defer cancel()
54+
ctx := context.Background()
5755

5856
var chart sourcev1.HelmChart
5957
if err := r.Get(ctx, req.NamespacedName, &chart); err != nil {
@@ -78,7 +76,7 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
7876
}
7977

8078
// get referenced chart repository
81-
repository, err := r.chartRepository(ctx, chart)
79+
repository, err := r.getChartRepositoryWithArtifact(ctx, chart)
8280
if err != nil {
8381
chart = sourcev1.HelmChartNotReady(*chart.DeepCopy(), sourcev1.ChartPullFailedReason, err.Error())
8482
if err := r.Status().Update(ctx, &chart); err != nil {
@@ -94,7 +92,7 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
9492
}
9593

9694
// try to pull chart
97-
pulledChart, err := r.sync(repository, *chart.DeepCopy())
95+
pulledChart, err := r.sync(ctx, repository, *chart.DeepCopy())
9896
if err != nil {
9997
log.Error(err, "Helm chart sync failed")
10098
if err := r.Status().Update(ctx, &pulledChart); err != nil {
@@ -132,7 +130,7 @@ func (r *HelmChartReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts
132130
Complete(r)
133131
}
134132

135-
func (r *HelmChartReconciler) sync(repository sourcev1.HelmRepository, chart sourcev1.HelmChart) (sourcev1.HelmChart, error) {
133+
func (r *HelmChartReconciler) sync(ctx context.Context, repository sourcev1.HelmRepository, chart sourcev1.HelmChart) (sourcev1.HelmChart, error) {
136134
indexBytes, err := ioutil.ReadFile(repository.Status.Artifact.Path)
137135
if err != nil {
138136
err = fmt.Errorf("failed to read Helm repository index file: %w", err)
@@ -182,7 +180,7 @@ func (r *HelmChartReconciler) sync(repository sourcev1.HelmRepository, chart sou
182180
}
183181

184182
var secret corev1.Secret
185-
err := r.Client.Get(context.TODO(), name, &secret)
183+
err := r.Client.Get(ctx, name, &secret)
186184
if err != nil {
187185
err = fmt.Errorf("auth secret error: %w", err)
188186
return sourcev1.HelmChartNotReady(chart, sourcev1.AuthenticationFailedReason, err.Error()), err
@@ -199,6 +197,8 @@ func (r *HelmChartReconciler) sync(repository sourcev1.HelmRepository, chart sou
199197
clientOpts = opts
200198
}
201199

200+
// TODO(hidde): implement timeout from the HelmRepository
201+
// https://github.com/helm/helm/pull/7950
202202
res, err := c.Get(u.String(), clientOpts...)
203203
if err != nil {
204204
return sourcev1.HelmChartNotReady(chart, sourcev1.ChartPullFailedReason, err.Error()), err
@@ -246,7 +246,10 @@ func (r *HelmChartReconciler) sync(repository sourcev1.HelmRepository, chart sou
246246
return sourcev1.HelmChartReady(chart, artifact, chartUrl, sourcev1.ChartPullSucceededReason, message), nil
247247
}
248248

249-
func (r *HelmChartReconciler) chartRepository(ctx context.Context, chart sourcev1.HelmChart) (sourcev1.HelmRepository, error) {
249+
// getChartRepositoryWithArtifact attempts to get the ChartRepository
250+
// for the given chart. It returns an error if the HelmRepository could
251+
// not be retrieved or if does not have an artifact.
252+
func (r *HelmChartReconciler) getChartRepositoryWithArtifact(ctx context.Context, chart sourcev1.HelmChart) (sourcev1.HelmRepository, error) {
250253
if chart.Spec.HelmRepositoryRef.Name == "" {
251254
return sourcev1.HelmRepository{}, fmt.Errorf("no HelmRepository reference given")
252255
}
@@ -270,6 +273,8 @@ func (r *HelmChartReconciler) chartRepository(ctx context.Context, chart sourcev
270273
return repository, err
271274
}
272275

276+
// shouldResetStatus returns a boolean indicating if the status of the
277+
// given chart should be reset and a reset HelmChartStatus.
273278
func (r *HelmChartReconciler) shouldResetStatus(chart sourcev1.HelmChart) (bool, sourcev1.HelmChartStatus) {
274279
resetStatus := false
275280
if chart.Status.Artifact != nil {
@@ -295,18 +300,23 @@ func (r *HelmChartReconciler) shouldResetStatus(chart sourcev1.HelmChart) (bool,
295300
}
296301
}
297302

303+
// gc performs a garbage collection on all but current artifacts of
304+
// the given chart.
298305
func (r *HelmChartReconciler) gc(chart sourcev1.HelmChart) error {
299306
if chart.Status.Artifact != nil {
300307
return r.Storage.RemoveAllButCurrent(*chart.Status.Artifact)
301308
}
302309
return nil
303310
}
304311

312+
// setOwnerRef appends the owner reference of the given chart to the
313+
// repository if it is not present.
305314
func (r *HelmChartReconciler) setOwnerRef(ctx context.Context, chart *sourcev1.HelmChart, repository sourcev1.HelmRepository) error {
306-
if !metav1.IsControlledBy(chart.GetObjectMeta(), repository.GetObjectMeta()) {
307-
chart.SetOwnerReferences(append(chart.GetOwnerReferences(),
308-
*metav1.NewControllerRef(repository.GetObjectMeta(), repository.GroupVersionKind())))
309-
return r.Update(ctx, chart)
315+
if metav1.IsControlledBy(chart.GetObjectMeta(), repository.GetObjectMeta()) {
316+
return nil
310317
}
311-
return nil
318+
chart.SetOwnerReferences(append(chart.GetOwnerReferences(), *metav1.NewControllerRef(
319+
repository.GetObjectMeta(), repository.GroupVersionKind(),
320+
)))
321+
return r.Update(ctx, chart)
312322
}

controllers/helmrepository_controller.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"io/ioutil"
2323
"net/url"
2424
"path"
25-
"time"
2625

2726
"github.com/go-logr/logr"
2827
"helm.sh/helm/v3/pkg/getter"
@@ -54,8 +53,7 @@ type HelmRepositoryReconciler struct {
5453
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=helmcharts/finalizers,verbs=get;update;patch
5554

5655
func (r *HelmRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
57-
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
58-
defer cancel()
56+
ctx := context.Background()
5957

6058
var repository sourcev1.HelmRepository
6159
if err := r.Get(ctx, req.NamespacedName, &repository); err != nil {
@@ -80,7 +78,7 @@ func (r *HelmRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
8078
}
8179

8280
// try to download index
83-
syncedRepo, err := r.sync(*repository.DeepCopy())
81+
syncedRepo, err := r.sync(ctx, *repository.DeepCopy())
8482
if err != nil {
8583
log.Error(err, "Helm repository sync failed")
8684
if err := r.Status().Update(ctx, &syncedRepo); err != nil {
@@ -117,7 +115,7 @@ func (r *HelmRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager,
117115
Complete(r)
118116
}
119117

120-
func (r *HelmRepositoryReconciler) sync(repository sourcev1.HelmRepository) (sourcev1.HelmRepository, error) {
118+
func (r *HelmRepositoryReconciler) sync(ctx context.Context, repository sourcev1.HelmRepository) (sourcev1.HelmRepository, error) {
121119
u, err := url.Parse(repository.Spec.URL)
122120
if err != nil {
123121
return sourcev1.HelmRepositoryNotReady(repository, sourcev1.URLInvalidReason, err.Error()), err
@@ -139,7 +137,7 @@ func (r *HelmRepositoryReconciler) sync(repository sourcev1.HelmRepository) (sou
139137
}
140138

141139
var secret corev1.Secret
142-
err := r.Client.Get(context.TODO(), name, &secret)
140+
err := r.Client.Get(ctx, name, &secret)
143141
if err != nil {
144142
err = fmt.Errorf("auth secret error: %w", err)
145143
return sourcev1.HelmRepositoryNotReady(repository, sourcev1.AuthenticationFailedReason, err.Error()), err
@@ -156,6 +154,8 @@ func (r *HelmRepositoryReconciler) sync(repository sourcev1.HelmRepository) (sou
156154
clientOpts = opts
157155
}
158156

157+
// TODO(hidde): implement timeout from the HelmRepository
158+
// https://github.com/helm/helm/pull/7950
159159
res, err := c.Get(u.String(), clientOpts...)
160160
if err != nil {
161161
return sourcev1.HelmRepositoryNotReady(repository, sourcev1.IndexationFailedReason, err.Error()), err
@@ -214,6 +214,8 @@ func (r *HelmRepositoryReconciler) sync(repository sourcev1.HelmRepository) (sou
214214
return sourcev1.HelmRepositoryReady(repository, artifact, indexURL, sourcev1.IndexationSucceededReason, message), nil
215215
}
216216

217+
// shouldResetStatus returns a boolean indicating if the status of the
218+
// given repository should be reset and a reset HelmChartStatus.
217219
func (r *HelmRepositoryReconciler) shouldResetStatus(repository sourcev1.HelmRepository) (bool, sourcev1.HelmRepositoryStatus) {
218220
resetStatus := false
219221
if repository.Status.Artifact != nil {
@@ -239,6 +241,8 @@ func (r *HelmRepositoryReconciler) shouldResetStatus(repository sourcev1.HelmRep
239241
}
240242
}
241243

244+
// gc performs a garbage collection on all but current artifacts of
245+
// the given repository.
242246
func (r *HelmRepositoryReconciler) gc(repository sourcev1.HelmRepository) error {
243247
if repository.Status.Artifact != nil {
244248
return r.Storage.RemoveAllButCurrent(*repository.Status.Artifact)

0 commit comments

Comments
 (0)