client.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package bluegreen
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. _ "github.com/golang/mock/mockgen/model"
  7. v1 "github.com/kakao/bluegreen/api/v1"
  8. appsv1 "k8s.io/api/apps/v1"
  9. corev1 "k8s.io/api/core/v1"
  10. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  11. ctrl "sigs.k8s.io/controller-runtime"
  12. "sigs.k8s.io/controller-runtime/pkg/client"
  13. "sigs.k8s.io/controller-runtime/pkg/reconcile"
  14. )
  15. //go:generate go run github.com/golang/mock/mockgen@v1.6.0 -package bluegreen -destination mock.gen.go . Client
  16. type Client interface {
  17. client.Reader
  18. CreateOrUpdateService(ctx context.Context, owner *v1.BlueGreen) error
  19. CreateOrUpdateDeployment(ctx context.Context, owner *v1.BlueGreen, phase v1.BlueOrGreen, podSpec corev1.PodSpec) error
  20. UpdateStatus(ctx context.Context, req ctrl.Request, status v1.BlueGreenStatus) error
  21. }
  22. var _ Client = &BlueGreenClient{}
  23. type BlueGreenClient struct {
  24. client.Client
  25. }
  26. func (r *BlueGreenClient) UpdateStatus(ctx context.Context, req reconcile.Request, status v1.BlueGreenStatus) error {
  27. return r.Status().Update(ctx, &v1.BlueGreen{
  28. ObjectMeta: metav1.ObjectMeta{
  29. Name: req.Name,
  30. Namespace: req.Namespace,
  31. },
  32. Status: status,
  33. })
  34. }
  35. func (r *BlueGreenClient) CreateOrUpdateDeployment(ctx context.Context, owner *v1.BlueGreen, phase v1.BlueOrGreen, podSpec corev1.PodSpec) error {
  36. deploy := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: owner.Namespace, Name: deploymentName(owner.Name, phase)}}
  37. if _, err := ctrl.CreateOrUpdate(ctx, r.Client, deploy, func() error {
  38. if err := ctrl.SetControllerReference(owner, deploy, r.Scheme()); err != nil {
  39. return err
  40. }
  41. label := map[string]string{
  42. "app.kubernetes.io/managed-by": "app.demo.kakao.com",
  43. "app.kubernetes.io/name": owner.Name,
  44. "app.kubernetes.io/phase": string(phase),
  45. }
  46. deploy.Spec.Selector = &metav1.LabelSelector{MatchLabels: label}
  47. deploy.Spec.Template = corev1.PodTemplateSpec{
  48. ObjectMeta: metav1.ObjectMeta{Labels: label},
  49. Spec: podSpec,
  50. }
  51. return nil
  52. }); err != nil {
  53. return err
  54. }
  55. return nil
  56. }
  57. func (r *BlueGreenClient) CreateOrUpdateService(ctx context.Context, owner *v1.BlueGreen) error {
  58. svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: owner.Namespace, Name: owner.Name}}
  59. if _, err := ctrl.CreateOrUpdate(ctx, r.Client, svc,
  60. func() error {
  61. if err := ctrl.SetControllerReference(owner, svc, r.Scheme()); err != nil {
  62. return err
  63. }
  64. svc.Spec.Ports = []corev1.ServicePort{
  65. {Name: "http", Protocol: corev1.ProtocolTCP, Port: 80},
  66. }
  67. svc.Spec.Selector = map[string]string{
  68. "app.kubernetes.io/managed-by": "app.demo.kakao.com",
  69. "app.kubernetes.io/name": owner.Name,
  70. "app.kubernetes.io/phase": string(owner.Spec.RouteTo),
  71. }
  72. return nil
  73. },
  74. ); err != nil {
  75. return err
  76. }
  77. return nil
  78. }
  79. func deploymentName(name string, phase v1.BlueOrGreen) string {
  80. return fmt.Sprintf("%s-%s", name, strings.ToLower(string(phase)))
  81. }