Wordpress operator for Kubernetes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.8KB

  1. package main
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "os"
  7. "runtime"
  8. // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
  9. _ "k8s.io/client-go/plugin/pkg/client/auth"
  10. "k8s.io/client-go/rest"
  11. "git.blindage.org/21h/wordpress-operator/pkg/apis"
  12. "git.blindage.org/21h/wordpress-operator/pkg/controller"
  13. "github.com/operator-framework/operator-sdk/pkg/k8sutil"
  14. kubemetrics "github.com/operator-framework/operator-sdk/pkg/kube-metrics"
  15. "github.com/operator-framework/operator-sdk/pkg/leader"
  16. "github.com/operator-framework/operator-sdk/pkg/log/zap"
  17. "github.com/operator-framework/operator-sdk/pkg/metrics"
  18. "github.com/operator-framework/operator-sdk/pkg/restmapper"
  19. sdkVersion "github.com/operator-framework/operator-sdk/version"
  20. "github.com/spf13/pflag"
  21. v1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/util/intstr"
  23. "sigs.k8s.io/controller-runtime/pkg/client/config"
  24. "sigs.k8s.io/controller-runtime/pkg/manager"
  25. logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
  26. "sigs.k8s.io/controller-runtime/pkg/runtime/signals"
  27. )
  28. // Change below variables to serve metrics on different host or port.
  29. var (
  30. metricsHost = "0.0.0.0"
  31. metricsPort int32 = 8383
  32. operatorMetricsPort int32 = 8686
  33. )
  34. var log = logf.Log.WithName("cmd")
  35. func printVersion() {
  36. log.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
  37. log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
  38. log.Info(fmt.Sprintf("Version of operator-sdk: %v", sdkVersion.Version))
  39. }
  40. func main() {
  41. // Add the zap logger flag set to the CLI. The flag set must
  42. // be added before calling pflag.Parse().
  43. pflag.CommandLine.AddFlagSet(zap.FlagSet())
  44. // Add flags registered by imported packages (e.g. glog and
  45. // controller-runtime)
  46. pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  47. pflag.Parse()
  48. // Use a zap logr.Logger implementation. If none of the zap
  49. // flags are configured (or if the zap flag set is not being
  50. // used), this defaults to a production zap logger.
  51. //
  52. // The logger instantiated here can be changed to any logger
  53. // implementing the logr.Logger interface. This logger will
  54. // be propagated through the whole operator, generating
  55. // uniform and structured logs.
  56. logf.SetLogger(zap.Logger())
  57. printVersion()
  58. namespace, err := k8sutil.GetWatchNamespace()
  59. if err != nil {
  60. log.Error(err, "Failed to get watch namespace")
  61. os.Exit(1)
  62. }
  63. // Get a config to talk to the apiserver
  64. cfg, err := config.GetConfig()
  65. if err != nil {
  66. log.Error(err, "")
  67. os.Exit(1)
  68. }
  69. ctx := context.TODO()
  70. // Become the leader before proceeding
  71. err = leader.Become(ctx, "wordpress-operator-lock")
  72. if err != nil {
  73. log.Error(err, "")
  74. os.Exit(1)
  75. }
  76. // Create a new Cmd to provide shared dependencies and start components
  77. mgr, err := manager.New(cfg, manager.Options{
  78. Namespace: namespace,
  79. MapperProvider: restmapper.NewDynamicRESTMapper,
  80. MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
  81. })
  82. if err != nil {
  83. log.Error(err, "")
  84. os.Exit(1)
  85. }
  86. log.Info("Registering Components.")
  87. // Setup Scheme for all resources
  88. if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
  89. log.Error(err, "")
  90. os.Exit(1)
  91. }
  92. // Setup all Controllers
  93. if err := controller.AddToManager(mgr); err != nil {
  94. log.Error(err, "")
  95. os.Exit(1)
  96. }
  97. if err = serveCRMetrics(cfg); err != nil {
  98. log.Info("Could not generate and serve custom resource metrics", "error", err.Error())
  99. }
  100. // Add to the below struct any other metrics ports you want to expose.
  101. servicePorts := []v1.ServicePort{
  102. {Port: metricsPort, Name: metrics.OperatorPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: metricsPort}},
  103. {Port: operatorMetricsPort, Name: metrics.CRPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: operatorMetricsPort}},
  104. }
  105. // Create Service object to expose the metrics port(s).
  106. service, err := metrics.CreateMetricsService(ctx, cfg, servicePorts)
  107. if err != nil {
  108. log.Info("Could not create metrics Service", "error", err.Error())
  109. }
  110. // CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources
  111. // necessary to configure Prometheus to scrape metrics from this operator.
  112. services := []*v1.Service{service}
  113. _, err = metrics.CreateServiceMonitors(cfg, namespace, services)
  114. if err != nil {
  115. log.Info("Could not create ServiceMonitor object", "error", err.Error())
  116. // If this operator is deployed to a cluster without the prometheus-operator running, it will return
  117. // ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation.
  118. if err == metrics.ErrServiceMonitorNotPresent {
  119. log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error())
  120. }
  121. }
  122. log.Info("Starting the Cmd.")
  123. // Start the Cmd
  124. if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
  125. log.Error(err, "Manager exited non-zero")
  126. os.Exit(1)
  127. }
  128. }
  129. // serveCRMetrics gets the Operator/CustomResource GVKs and generates metrics based on those types.
  130. // It serves those metrics on "http://metricsHost:operatorMetricsPort".
  131. func serveCRMetrics(cfg *rest.Config) error {
  132. // Below function returns filtered operator/CustomResource specific GVKs.
  133. // For more control override the below GVK list with your own custom logic.
  134. filteredGVK, err := k8sutil.GetGVKsFromAddToScheme(apis.AddToScheme)
  135. if err != nil {
  136. return err
  137. }
  138. // Get the namespace the operator is currently deployed in.
  139. operatorNs, err := k8sutil.GetOperatorNamespace()
  140. if err != nil {
  141. return err
  142. }
  143. // To generate metrics in other namespaces, add the values below.
  144. ns := []string{operatorNs}
  145. // Generate and serve custom resource specific metrics.
  146. err = kubemetrics.GenerateAndServeCRMetrics(cfg, ns, filteredGVK, metricsHost, operatorMetricsPort)
  147. if err != nil {
  148. return err
  149. }
  150. return nil
  151. }