|
| 1 | +package cmd |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "strings" |
| 7 | + |
| 8 | + mariadbv1 "github.com/amazeeio/dbaas-operator/apis/mariadb/v1" |
| 9 | + mongodbv1 "github.com/amazeeio/dbaas-operator/apis/mongodb/v1" |
| 10 | + postgresv1 "github.com/amazeeio/dbaas-operator/apis/postgres/v1" |
| 11 | + "github.com/spf13/cobra" |
| 12 | + "github.com/uselagoon/build-deploy-tool/internal/collector" |
| 13 | + "github.com/uselagoon/build-deploy-tool/internal/generator" |
| 14 | + "github.com/uselagoon/build-deploy-tool/internal/helpers" |
| 15 | + "github.com/uselagoon/build-deploy-tool/internal/k8s" |
| 16 | + appsv1 "k8s.io/api/apps/v1" |
| 17 | + corev1 "k8s.io/api/core/v1" |
| 18 | +) |
| 19 | + |
| 20 | +var cleanupCmd = &cobra.Command{ |
| 21 | + Use: "cleanup", |
| 22 | + Aliases: []string{"clean", "cu", "c"}, |
| 23 | + Short: "Cleanup old services", |
| 24 | + RunE: func(cmd *cobra.Command, args []string) error { |
| 25 | + deleteServices, err := cmd.Flags().GetBool("delete") |
| 26 | + if err != nil { |
| 27 | + return fmt.Errorf("error reading domain flag: %v", err) |
| 28 | + } |
| 29 | + client, err := k8s.NewClient() |
| 30 | + if err != nil { |
| 31 | + return err |
| 32 | + } |
| 33 | + // create a collector |
| 34 | + col := collector.NewCollector(client) |
| 35 | + gen, err := generator.GenerateInput(*rootCmd, false) |
| 36 | + if err != nil { |
| 37 | + return err |
| 38 | + } |
| 39 | + images, err := rootCmd.PersistentFlags().GetString("images") |
| 40 | + if err != nil { |
| 41 | + return fmt.Errorf("error reading images flag: %v", err) |
| 42 | + } |
| 43 | + imageRefs, err := loadImagesFromFile(images) |
| 44 | + if err != nil { |
| 45 | + return err |
| 46 | + } |
| 47 | + namespace := helpers.GetEnv("NAMESPACE", "", false) |
| 48 | + namespace, err = helpers.GetNamespace(namespace, "/var/run/secrets/kubernetes.io/serviceaccount/namespace") |
| 49 | + if err != nil { |
| 50 | + return err |
| 51 | + } |
| 52 | + if namespace == "" { |
| 53 | + return fmt.Errorf("unable to detect namespace") |
| 54 | + } |
| 55 | + gen.Namespace = namespace |
| 56 | + gen.ImageReferences = imageRefs.Images |
| 57 | + _, _, _, _, _, _, err = RunCleanup(col, gen, deleteServices) |
| 58 | + if err != nil { |
| 59 | + return err |
| 60 | + } |
| 61 | + return nil |
| 62 | + }, |
| 63 | +} |
| 64 | + |
| 65 | +func RunCleanup(c *collector.Collector, gen generator.GeneratorInput, deleteServices bool) ([]string, []string, []string, []string, []string, []string, error) { |
| 66 | + out, err := LagoonServiceTemplateIdentification(gen) |
| 67 | + if err != nil { |
| 68 | + return nil, nil, nil, nil, nil, nil, err |
| 69 | + } |
| 70 | + |
| 71 | + dbaas, err := IdentifyDBaaSConsumers(gen) |
| 72 | + if err != nil { |
| 73 | + return nil, nil, nil, nil, nil, nil, err |
| 74 | + } |
| 75 | + |
| 76 | + state, err := c.Collect(context.Background(), gen.Namespace) |
| 77 | + if err != nil { |
| 78 | + return nil, nil, nil, nil, nil, nil, err |
| 79 | + } |
| 80 | + |
| 81 | + mariadbMatch := false |
| 82 | + var mariadbDelete []mariadbv1.MariaDBConsumer |
| 83 | + var mariadbDeleteS []string |
| 84 | + for _, exist := range state.MariaDBConsumers.Items { |
| 85 | + for _, prov := range dbaas { |
| 86 | + sp := strings.Split(prov, ":") |
| 87 | + if strings.Contains(sp[1], "mariadb-dbaas") { |
| 88 | + if exist.Name == sp[0] { |
| 89 | + mariadbMatch = true |
| 90 | + continue |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + if !mariadbMatch { |
| 95 | + mariadbDelete = append(mariadbDelete, exist) |
| 96 | + mariadbDeleteS = append(mariadbDeleteS, exist.Name) |
| 97 | + } |
| 98 | + mariadbMatch = false |
| 99 | + } |
| 100 | + |
| 101 | + mongodbMatch := false |
| 102 | + var mongodbDelete []mongodbv1.MongoDBConsumer |
| 103 | + var mongodbDeleteS []string |
| 104 | + for _, exist := range state.MongoDBConsumers.Items { |
| 105 | + for _, prov := range dbaas { |
| 106 | + sp := strings.Split(prov, ":") |
| 107 | + if strings.Contains(sp[1], "mongodb-dbaas") { |
| 108 | + if exist.Name == sp[0] { |
| 109 | + mongodbMatch = true |
| 110 | + continue |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | + if !mongodbMatch { |
| 115 | + mongodbDelete = append(mongodbDelete, exist) |
| 116 | + mongodbDeleteS = append(mongodbDeleteS, exist.Name) |
| 117 | + } |
| 118 | + mongodbMatch = false |
| 119 | + } |
| 120 | + |
| 121 | + postgresqlMatch := false |
| 122 | + var postgresqlDelete []postgresv1.PostgreSQLConsumer |
| 123 | + var postgresqlDeleteS []string |
| 124 | + for _, exist := range state.PostgreSQLConsumers.Items { |
| 125 | + for _, prov := range dbaas { |
| 126 | + sp := strings.Split(prov, ":") |
| 127 | + if strings.Contains(sp[1], "postgres-dbaas") { |
| 128 | + if exist.Name == sp[0] { |
| 129 | + postgresqlMatch = true |
| 130 | + continue |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + if !postgresqlMatch { |
| 135 | + postgresqlDelete = append(postgresqlDelete, exist) |
| 136 | + postgresqlDeleteS = append(postgresqlDeleteS, exist.Name) |
| 137 | + } |
| 138 | + postgresqlMatch = false |
| 139 | + } |
| 140 | + |
| 141 | + depMatch := false |
| 142 | + var depDelete []appsv1.Deployment |
| 143 | + var depDeleteS []string |
| 144 | + for _, exist := range state.Deployments.Items { |
| 145 | + for _, prov := range out.Deployments { |
| 146 | + if exist.Name == prov { |
| 147 | + depMatch = true |
| 148 | + continue |
| 149 | + } |
| 150 | + } |
| 151 | + if !depMatch { |
| 152 | + depDelete = append(depDelete, exist) |
| 153 | + depDeleteS = append(depDeleteS, exist.Name) |
| 154 | + } |
| 155 | + depMatch = false |
| 156 | + } |
| 157 | + |
| 158 | + volMatch := false |
| 159 | + var volDelete []corev1.PersistentVolumeClaim |
| 160 | + var volDeleteS []string |
| 161 | + for _, exist := range state.PVCs.Items { |
| 162 | + for _, prov := range out.Volumes { |
| 163 | + if exist.Name == prov { |
| 164 | + volMatch = true |
| 165 | + continue |
| 166 | + } |
| 167 | + } |
| 168 | + if !volMatch { |
| 169 | + volDelete = append(volDelete, exist) |
| 170 | + volDeleteS = append(volDeleteS, exist.Name) |
| 171 | + } |
| 172 | + volMatch = false |
| 173 | + } |
| 174 | + |
| 175 | + servMatch := false |
| 176 | + var servDelete []corev1.Service |
| 177 | + var servDeleteS []string |
| 178 | + for _, exist := range state.Services.Items { |
| 179 | + for _, prov := range out.Services { |
| 180 | + if exist.Name == prov { |
| 181 | + servMatch = true |
| 182 | + continue |
| 183 | + } |
| 184 | + } |
| 185 | + if !servMatch { |
| 186 | + servDelete = append(servDelete, exist) |
| 187 | + servDeleteS = append(servDeleteS, exist.Name) |
| 188 | + } |
| 189 | + servMatch = false |
| 190 | + } |
| 191 | + |
| 192 | + if len(mariadbDeleteS) > 0 || len(mongodbDeleteS) > 0 || len(postgresqlDeleteS) > 0 || len(depDeleteS) > 0 || len(volDeleteS) > 0 || len(servDeleteS) > 0 { |
| 193 | + fmt.Println(`>> Lagoon detected services or volumes that have been removed from the docker-compose file`) |
| 194 | + if !deleteServices { |
| 195 | + fmt.Println(`> If you no longer need these services, you can instruct Lagoon to remove it from the environment by setting the following variable |
| 196 | + 'LAGOON_FEATURE_FLAG_CLEANUP_REMOVED_LAGOON_SERVICES=enabled' as a GLOBAL scoped variable to this environment or project. |
| 197 | + Removing unused resources will result in the services and any data they had being deleted. |
| 198 | + Ensure your application is no longer configured to use these resources before removing them. |
| 199 | + If you're not sure, contact your support team with a link to this build.`) |
| 200 | + } else { |
| 201 | + fmt.Println(`> The flag 'LAGOON_FEATURE_FLAG_CLEANUP_REMOVED_LAGOON_SERVICES' is enabled. |
| 202 | + Resources that were removed from the docker-compose file will now be removed from the environment. |
| 203 | + The services and any data they had will be deleted. |
| 204 | + You should remove this variable if you don't want services to be removed automatically in the future.`) |
| 205 | + } |
| 206 | + fmt.Println(`> Future releases of Lagoon may remove services automatically, you should ensure that your services are up always up to date if you see this warning."`) |
| 207 | + |
| 208 | + for _, i := range depDelete { |
| 209 | + if deleteServices { |
| 210 | + fmt.Printf(">> Removing deployment %s\n", i.Name) |
| 211 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 212 | + return nil, nil, nil, nil, nil, nil, err |
| 213 | + } |
| 214 | + } else { |
| 215 | + fmt.Printf(">> Would remove deployment %s\n", i.Name) |
| 216 | + } |
| 217 | + } |
| 218 | + for _, i := range volDelete { |
| 219 | + if deleteServices { |
| 220 | + fmt.Printf(">> Removing volume %s\n", i.Name) |
| 221 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 222 | + return nil, nil, nil, nil, nil, nil, err |
| 223 | + } |
| 224 | + } else { |
| 225 | + fmt.Printf(">> Would remove volume %s\n", i.Name) |
| 226 | + } |
| 227 | + } |
| 228 | + for _, i := range servDelete { |
| 229 | + if deleteServices { |
| 230 | + fmt.Printf(">> Removing service %s\n", i.Name) |
| 231 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 232 | + return nil, nil, nil, nil, nil, nil, err |
| 233 | + } |
| 234 | + } else { |
| 235 | + fmt.Printf(">> Would remove service %s\n", i.Name) |
| 236 | + } |
| 237 | + } |
| 238 | + for _, i := range mariadbDelete { |
| 239 | + if deleteServices { |
| 240 | + fmt.Printf(">> Removing mariadb consumer %s\n", i.Name) |
| 241 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 242 | + return nil, nil, nil, nil, nil, nil, err |
| 243 | + } |
| 244 | + } else { |
| 245 | + fmt.Printf(">> Would remove mariadb consumer %s\n", i.Name) |
| 246 | + } |
| 247 | + } |
| 248 | + for _, i := range mongodbDelete { |
| 249 | + if deleteServices { |
| 250 | + fmt.Printf(">> Removing mongodb consumer %s\n", i.Name) |
| 251 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 252 | + return nil, nil, nil, nil, nil, nil, err |
| 253 | + } |
| 254 | + } else { |
| 255 | + fmt.Printf(">> Would remove mongodb consumer %s\n", i.Name) |
| 256 | + } |
| 257 | + } |
| 258 | + for _, i := range postgresqlDelete { |
| 259 | + if deleteServices { |
| 260 | + fmt.Printf(">> Removing postgresql consumer %s\n", i.Name) |
| 261 | + if err := c.Client.Delete(context.Background(), &i); err != nil { |
| 262 | + return nil, nil, nil, nil, nil, nil, err |
| 263 | + } |
| 264 | + } else { |
| 265 | + fmt.Printf(">> Would remove postgresql consumer %s\n", i.Name) |
| 266 | + } |
| 267 | + } |
| 268 | + return mariadbDeleteS, mongodbDeleteS, postgresqlDeleteS, depDeleteS, volDeleteS, servDeleteS, nil |
| 269 | + } else { |
| 270 | + return nil, nil, nil, nil, nil, nil, nil |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +func init() { |
| 275 | + runCmd.AddCommand(cleanupCmd) |
| 276 | + cleanupCmd.Flags().Bool("delete", false, "flag to actually delete services") |
| 277 | +} |
0 commit comments