|
|
|
@@ -75,12 +75,6 @@ func makePackageWatcher(logger *zap.Logger, fissionClient *crd.FissionClient, k8
|
|
|
|
|
// 6. Update package status to succeed state
|
|
|
|
|
// *. Update package status to failed state,if any one of steps above failed/time out
|
|
|
|
|
func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *fv1.Package) {
|
|
|
|
|
|
|
|
|
|
// Ignore non-pending state packages.
|
|
|
|
|
if srcpkg.Status.BuildStatus != fv1.BuildStatusPending {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignore duplicate build requests
|
|
|
|
|
key := fmt.Sprintf("%v-%v", srcpkg.ObjectMeta.Name, srcpkg.ObjectMeta.ResourceVersion)
|
|
|
|
|
_, err := buildCache.Set(key, srcpkg)
|
|
|
|
@@ -228,20 +222,76 @@ func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *fv1.Package)
|
|
|
|
|
zap.String("package", fmt.Sprintf("%s.%s", pkg.ObjectMeta.Name, pkg.ObjectMeta.Namespace)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pkgw *packageWatcher) watchPackages(fissionClient *crd.FissionClient,
|
|
|
|
|
kubernetesClient *kubernetes.Clientset, builderNamespace string) {
|
|
|
|
|
func (pkgw *packageWatcher) watchPackages() {
|
|
|
|
|
buildCache := cache.MakeCache(0, 0)
|
|
|
|
|
lw := k8sCache.NewListWatchFromClient(pkgw.fissionClient.CoreV1().RESTClient(), "packages", apiv1.NamespaceAll, fields.Everything())
|
|
|
|
|
pkgStore, controller := k8sCache.NewInformer(lw, &fv1.Package{}, 60*time.Second, k8sCache.ResourceEventHandlerFuncs{
|
|
|
|
|
|
|
|
|
|
processPkg := func(pkg *fv1.Package) {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
if len(pkg.Status.BuildStatus) == 0 {
|
|
|
|
|
_, err = setInitialBuildStatus(pkgw.fissionClient, pkg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
pkgw.logger.Error("error filling package status", zap.Error(err))
|
|
|
|
|
}
|
|
|
|
|
// once we update the package status, an update event
|
|
|
|
|
// will arrive and handle by UpdateFunc later. So we
|
|
|
|
|
// don't need to build the package at this moment.
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only build pending state packages.
|
|
|
|
|
if pkg.Status.BuildStatus == fv1.BuildStatusPending {
|
|
|
|
|
go pkgw.build(buildCache, pkg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkgStore, controller := k8sCache.NewInformer(lw, &fv1.Package{}, 60*time.Minute, k8sCache.ResourceEventHandlerFuncs{
|
|
|
|
|
AddFunc: func(obj interface{}) {
|
|
|
|
|
pkg := obj.(*fv1.Package)
|
|
|
|
|
go pkgw.build(buildCache, pkg)
|
|
|
|
|
processPkg(pkg)
|
|
|
|
|
},
|
|
|
|
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
|
|
|
oldPkg := oldObj.(*fv1.Package)
|
|
|
|
|
pkg := newObj.(*fv1.Package)
|
|
|
|
|
go pkgw.build(buildCache, pkg)
|
|
|
|
|
|
|
|
|
|
// TODO: Once enable "/status", check generation for spec changed instead.
|
|
|
|
|
// Before "/status" is enabled, the generation and resource version will be changed
|
|
|
|
|
// if we update the status of a package, hence we are not able to differentiate
|
|
|
|
|
// the spec change or status change. So we only build package which's status
|
|
|
|
|
// us "pending" and user have to use "kubectl replace" to update a package.
|
|
|
|
|
if oldPkg.ResourceVersion == pkg.ResourceVersion &&
|
|
|
|
|
pkg.Status.BuildStatus != fv1.BuildStatusPending {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
processPkg(pkg)
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
pkgw.pkgStore = pkgStore
|
|
|
|
|
controller.Run(make(chan struct{}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setInitialBuildStatus sets initial build status to a package if it is empty.
|
|
|
|
|
// This normally occurs when the user applies package YAML files that have no status field
|
|
|
|
|
// through kubectl.
|
|
|
|
|
func setInitialBuildStatus(fissionClient *crd.FissionClient, pkg *fv1.Package) (*fv1.Package, error) {
|
|
|
|
|
pkg.Status = fv1.PackageStatus{
|
|
|
|
|
LastUpdateTimestamp: metav1.Time{Time: time.Now().UTC()},
|
|
|
|
|
}
|
|
|
|
|
if !pkg.Spec.Deployment.IsEmpty() {
|
|
|
|
|
// if the deployment archive is not empty,
|
|
|
|
|
// we assume it's a deployable package no matter
|
|
|
|
|
// the source archive is empty or not.
|
|
|
|
|
pkg.Status.BuildStatus = fv1.BuildStatusNone
|
|
|
|
|
} else if !pkg.Spec.Source.IsEmpty() {
|
|
|
|
|
pkg.Status.BuildStatus = fv1.BuildStatusPending
|
|
|
|
|
} else {
|
|
|
|
|
// mark package failed since we cannot do anything with it.
|
|
|
|
|
pkg.Status.BuildStatus = fv1.BuildStatusFailed
|
|
|
|
|
pkg.Status.BuildLog = "Both deploy and source archive are empty"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: use UpdateStatus to update status
|
|
|
|
|
return fissionClient.CoreV1().Packages(pkg.Namespace).Update(pkg)
|
|
|
|
|
}
|
|
|
|
|