Skip to content

Instantly share code, notes, and snippets.

@alexeldeib
Last active January 16, 2020 03:49
Show Gist options
  • Save alexeldeib/b311d6a8adc1579ad05ad032ad0193a7 to your computer and use it in GitHub Desktop.
Save alexeldeib/b311d6a8adc1579ad05ad032ad0193a7 to your computer and use it in GitHub Desktop.
apply runtime objects from urls approximation
// // Build and apply kustomized objects
// if obj.Spec.Kustomizations != nil {
// // Initialize for kustomization
// // ace: can't use memfs until git cloner is fixed upstream
// // ace: real fs + git exec used here https://github.com/kubernetes-sigs/kustomize/blob/186df6f7c8aa28774be8f54fa000bf99e95642d6/api/filesys/confirmeddir.go#L20-L31
// fs := filesys.MakeFsOnDisk()
// koptions := krusty.MakeDefaultOptions()
// kustomizer := krusty.MakeKustomizer(fs, koptions)
// // Potentially we may have many kustomizations to apply.
// for _, path := range obj.Spec.Kustomizations {
// // Kustomize build
// resmap, err := kustomizer.Run(path)
// if err != nil {
// return ctrl.Result{}, err
// }
// // We need to extract runtime.Objects from the Kustomize out to apply them with our kubeclient.
// // The easiest way to do so is to convert everything to yaml, and decode via separators (---)
// // This gives us an array of runtime.Objects which we can directly CreateOrUpdate on the remote cluster.
// data, err := resmap.AsYaml()
// if err != nil {
// return ctrl.Result{}, err
// }
// resources = append(resources, data)
// // buf := bytes.NewBuffer(data)
// // d := decoder.NewYAMLDecoder(ioutil.NopCloser(buf), r.Scheme)
// // output, err := decode(d, log)
// // if err != nil {
// // return ctrl.Result{}, err
// // }
// // resources = append(resources, output...)
// }
// }
// if obj.Spec.Manifests != nil {
// httpclient := &http.Client{
// Timeout: time.Second * 10,
// Transport: &http.Transport{
// Dial: (&net.Dialer{
// Timeout: 5 * time.Second,
// }).Dial,
// TLSHandshakeTimeout: 5 * time.Second,
// },
// }
// for i := range obj.Spec.Manifests {
// response, err := httpclient.Get(obj.Spec.Manifests[i])
// if err != nil {
// return ctrl.Result{}, err
// }
// b, err := ioutil.ReadAll(response.Body)
// if err != nil {
// return ctrl.Result{}, err
// }
// resources = append(resources, b)
// // d := decoder.NewYAMLDecoder(, r.Scheme)
// // output, err := decode(d, log)
// // if err != nil {
// // return ctrl.Result{}, err
// // }
// // resources = append(resources, output...)
// }
// }
// if obj.Spec.Kustomizations != nil || obj.Spec.Manifests != nil {
// getter, err := remote.NewRESTClientGetter(kubeconfigBytes)
// if err != nil {
// return ctrl.Result{}, err
// }
// factory := cmdutil.NewFactory(getter)
// for i := range obj.Spec.Kustomizations {
// url := obj.Spec.Kustomizations[i]
// stdio := bytes.NewBuffer(nil)
// errio := bytes.NewBuffer(nil)
// streams := genericclioptions.IOStreams{In: stdio, Out: stdio, ErrOut: errio}
// cmd := apply.NewCmdApply("kubectl", factory, streams)
// opts := apply.NewApplyOptions(streams)
// opts.DeleteFlags.FileNameFlags.Kustomize = &url
// if err := opts.Complete(factory, cmd); err != nil {
// log.Error(err, "failed to complete apply options")
// return ctrl.Result{}, err
// }
// if err := opts.Run(); err != nil {
// log.Error(err, "failed to apply")
// return ctrl.Result{}, err
// }
// log.V(2).Info("output", "stdio", stdio.String(), "errio", errio.String())
// }
// if obj.Spec.Manifests != nil {
// stdio := bytes.NewBuffer(nil)
// errio := bytes.NewBuffer(nil)
// streams := genericclioptions.IOStreams{In: stdio, Out: stdio, ErrOut: errio}
// cmd := apply.NewCmdApply("kubectl", factory, streams)
// opts := apply.NewApplyOptions(streams)
// opts.DeleteFlags.FileNameFlags.Filenames = &obj.Spec.Manifests
// if err := opts.Complete(factory, cmd); err != nil {
// log.Error(err, "failed to complete apply options")
// return ctrl.Result{}, err
// }
// if err := opts.Run(); err != nil {
// log.Error(err, "failed to apply")
// return ctrl.Result{}, err
// }
// log.V(2).Info("output", "stdio", stdio.String(), "errio", errio.String())
// }
// }
// }
var objects []runtime.Object
// Build and apply kustomized objects
if obj.Spec.Kustomizations != nil {
// Initialize for kustomization
// ace: can't use memfs until git cloner is fixed upstream
// ace: real fs + git exec used here https://github.com/kubernetes-sigs/kustomize/blob/186df6f7c8aa28774be8f54fa000bf99e95642d6/api/filesys/confirmeddir.go#L20-L31
fs := filesys.MakeFsOnDisk()
koptions := krusty.MakeDefaultOptions()
kustomizer := krusty.MakeKustomizer(fs, koptions)
// Potentially we may have many kustomizations to apply.
for _, path := range obj.Spec.Kustomizations {
// Kustomize build
resmap, err := kustomizer.Run(path)
if err != nil {
return ctrl.Result{}, err
}
// We need to extract runtime.Objects from the Kustomize out to apply them with our kubeclient.
// The easiest way to do so is to convert everything to yaml, and decode via separators (---)
// This gives us an array of runtime.Objects which we can directly CreateOrUpdate on the remote cluster.
data, err := resmap.AsYaml()
if err != nil {
return ctrl.Result{}, err
}
buf := bytes.NewBuffer(data)
d := decoder.NewYAMLDecoder(ioutil.NopCloser(buf), r.Scheme)
output, err := decode(d, log)
if err != nil {
return ctrl.Result{}, err
}
objects = append(objects, output...)
}
}
if obj.Spec.Manifests != nil {
httpclient := &http.Client{
Timeout: time.Second * 10,
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
}).Dial,
TLSHandshakeTimeout: 5 * time.Second,
},
}
for i := range obj.Spec.Manifests {
response, err := httpclient.Get(obj.Spec.Manifests[i])
if err != nil {
return ctrl.Result{}, err
}
d := decoder.NewYAMLDecoder(response.Body, r.Scheme)
output, err := decode(d, log)
if err != nil {
return ctrl.Result{}, err
}
objects = append(objects, output...)
}
}
// TODO(ace): this probably won't scale...we are basically polling every minute and applying all resources
// Apply any/all objects we found!
if objects != nil {
// Construct remote client
// TODO(ace): simplify. If we can remove dep on clientcmd, we can run manager.exe on windows again.
clientconfig, err := clientcmd.NewClientConfigFromBytes(kubeconfigBytes)
if err != nil {
return ctrl.Result{}, err
}
restClient, err := clientconfig.ClientConfig()
if err != nil {
return ctrl.Result{}, err
}
kubeclient, err := client.New(restClient, client.Options{
Scheme: r.Scheme,
})
if err != nil {
return ctrl.Result{}, err
}
// Apply objects output from kustomization, one by one
for i := range objects {
if _, err := controllerutil.CreateOrUpdate(ctx, kubeclient, objects[i], func() error { return nil }); err != nil {
metaObj, _ := objects[i].(metav1.Object)
log.WithName("target").WithValues("gvk", objects[i].GetObjectKind().GroupVersionKind().String(), "name", metaObj.GetName(), "namespace", metaObj.GetNamespace()).Error(err, "")
return ctrl.Result{}, errors.Wrap(err, "failed to create object")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment