Merge "Adds command objects for cluster check-certificate-expiration
"
This commit is contained in:
commit
084ed45ef3
@ -17,8 +17,9 @@ package checkexpiration
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/checkexpiration"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/errors"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
"opendev.org/airship/airshipctl/pkg/log"
|
||||
)
|
||||
|
||||
@ -54,25 +55,31 @@ airshipctl cluster check-certificate-expiration -t 30 -o yaml --kubeconfig testc
|
||||
|
||||
// NewCheckCommand creates a new command for generating secret information
|
||||
func NewCheckCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
var threshold int
|
||||
var contentType, kubeconfig string
|
||||
c := &checkexpiration.CheckCommand{
|
||||
Options: checkexpiration.CheckFlags{},
|
||||
CfgFactory: cfgFactory,
|
||||
ClientFactory: client.DefaultClient,
|
||||
}
|
||||
|
||||
checkCmd := &cobra.Command{
|
||||
Use: "check-certificate-expiration",
|
||||
Short: "Check for expiring TLS certificates, secrets and kubeconfigs in the kubernetes cluster",
|
||||
Long: checkLong[1:],
|
||||
Example: checkExample,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return errors.ErrNotImplemented{What: "check certificate expiration"}
|
||||
return c.RunE(cmd.OutOrStdout())
|
||||
},
|
||||
}
|
||||
|
||||
checkCmd.Flags().IntVarP(&threshold, "threshold", "t", -1,
|
||||
checkCmd.Flags().IntVarP(&c.Options.Threshold, "threshold", "t", -1,
|
||||
"The max expiration threshold in days before a certificate is"+
|
||||
" expiring. Displays all the certificates by default")
|
||||
checkCmd.Flags().StringVarP(&contentType, "output", "o", "json", "Convert "+
|
||||
checkCmd.Flags().StringVarP(&c.Options.FormatType, "output", "o", "json", "Convert "+
|
||||
"output to yaml or json")
|
||||
checkCmd.Flags().StringVar(&kubeconfig, kubeconfigFlag, "",
|
||||
checkCmd.Flags().StringVar(&c.Options.Kubeconfig, kubeconfigFlag, "",
|
||||
"Path to kubeconfig associated with cluster being managed")
|
||||
checkCmd.Flags().StringVar(&c.Options.KubeContext, "kubecontext", "",
|
||||
"Kubeconfig context to be used")
|
||||
|
||||
err := checkCmd.MarkFlagRequired(kubeconfigFlag)
|
||||
if err != nil {
|
||||
|
@ -30,5 +30,6 @@ airshipctl cluster check-certificate-expiration -t 30 -o yaml --kubeconfig testc
|
||||
Flags:
|
||||
-h, --help help for check-certificate-expiration
|
||||
--kubeconfig string Path to kubeconfig associated with cluster being managed
|
||||
--kubecontext string Kubeconfig context to be used
|
||||
-o, --output string Convert output to yaml or json (default "json")
|
||||
-t, --threshold int The max expiration threshold in days before a certificate is expiring. Displays all the certificates by default (default -1)
|
||||
|
@ -42,6 +42,7 @@ airshipctl cluster check-certificate-expiration -t 30 -o yaml --kubeconfig testc
|
||||
```
|
||||
-h, --help help for check-certificate-expiration
|
||||
--kubeconfig string Path to kubeconfig associated with cluster being managed
|
||||
--kubecontext string Kubeconfig context to be used
|
||||
-o, --output string Convert output to yaml or json (default "json")
|
||||
-t, --threshold int The max expiration threshold in days before a certificate is expiring. Displays all the certificates by default (default -1)
|
||||
```
|
||||
|
60
pkg/cluster/checkexpiration/checkexpiration.go
Normal file
60
pkg/cluster/checkexpiration/checkexpiration.go
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package checkexpiration
|
||||
|
||||
import (
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/errors"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
)
|
||||
|
||||
// CertificateExpirationStore is the customized client store
|
||||
type CertificateExpirationStore struct {
|
||||
Kclient client.Interface
|
||||
Settings config.Factory
|
||||
}
|
||||
|
||||
// Expiration captures expiration information of all expirable entities in the cluster
|
||||
type Expiration struct{}
|
||||
|
||||
// NewStore returns an instance of a CertificateExpirationStore
|
||||
func NewStore(cfgFactory config.Factory, clientFactory client.Factory,
|
||||
kubeconfig string, _ string) (CertificateExpirationStore, error) {
|
||||
airshipconfig, err := cfgFactory()
|
||||
if err != nil {
|
||||
return CertificateExpirationStore{}, err
|
||||
}
|
||||
|
||||
// TODO (guhan) Allow kube context to be passed to client Factory
|
||||
// 4th argument in NewStore takes kube context and is ignored for now.
|
||||
// To be modified post #388. Refer to
|
||||
// https://review.opendev.org/#/c/760501/7/pkg/cluster/checkexpiration/command.go@31
|
||||
kclient, err := clientFactory(airshipconfig.LoadedConfigPath(), kubeconfig)
|
||||
if err != nil {
|
||||
return CertificateExpirationStore{}, err
|
||||
}
|
||||
|
||||
return CertificateExpirationStore{
|
||||
Kclient: kclient,
|
||||
Settings: cfgFactory,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetExpiringCertificates checks for the expiration data
|
||||
// NOT IMPLEMENTED (guhan)
|
||||
// TODO (guhan) check for TLS certificates, workload kubeconfig and node certificates
|
||||
func (store CertificateExpirationStore) GetExpiringCertificates(expirationThreshold int) (Expiration, error) {
|
||||
return Expiration{}, errors.ErrNotImplemented{What: "check certificate expiration logic"}
|
||||
}
|
73
pkg/cluster/checkexpiration/command.go
Normal file
73
pkg/cluster/checkexpiration/command.go
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package checkexpiration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
"opendev.org/airship/airshipctl/pkg/util/yaml"
|
||||
)
|
||||
|
||||
// CheckFlags flags given for checking the expiration
|
||||
type CheckFlags struct {
|
||||
Threshold int
|
||||
FormatType string
|
||||
Kubeconfig string
|
||||
KubeContext string
|
||||
}
|
||||
|
||||
// CheckCommand check expiration command
|
||||
type CheckCommand struct {
|
||||
Options CheckFlags
|
||||
CfgFactory config.Factory
|
||||
ClientFactory client.Factory
|
||||
}
|
||||
|
||||
// RunE is the implementation of check command
|
||||
func (c *CheckCommand) RunE(w io.Writer) error {
|
||||
if !strings.EqualFold(c.Options.FormatType, "json") && !strings.EqualFold(c.Options.FormatType, "yaml") {
|
||||
return ErrInvalidFormat{RequestedFormat: c.Options.FormatType}
|
||||
}
|
||||
|
||||
secretStore, err := NewStore(c.CfgFactory, c.ClientFactory, c.Options.Kubeconfig, c.Options.KubeContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expirationInfo, err := secretStore.GetExpiringCertificates(c.Options.Threshold)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Options.FormatType == "yaml" {
|
||||
err = yaml.WriteOut(w, expirationInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
buffer, err := json.MarshalIndent(expirationInfo, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
106
pkg/cluster/checkexpiration/command_test.go
Normal file
106
pkg/cluster/checkexpiration/command_test.go
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package checkexpiration_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/checkexpiration"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client/fake"
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
)
|
||||
|
||||
const (
|
||||
testNotImplementedErr = "not implemented: check certificate expiration logic"
|
||||
)
|
||||
|
||||
func TestRunE(t *testing.T) {
|
||||
tests := []struct {
|
||||
testCaseName string
|
||||
testErr string
|
||||
checkFlags checkexpiration.CheckFlags
|
||||
cfgFactory config.Factory
|
||||
expectedOutput string
|
||||
}{
|
||||
{
|
||||
testCaseName: "invalid-input-format",
|
||||
cfgFactory: func() (*config.Config, error) {
|
||||
return nil, nil
|
||||
},
|
||||
checkFlags: checkexpiration.CheckFlags{
|
||||
Threshold: 0,
|
||||
FormatType: "test-yaml",
|
||||
},
|
||||
testErr: checkexpiration.ErrInvalidFormat{RequestedFormat: "test-yaml"}.Error(),
|
||||
},
|
||||
{
|
||||
testCaseName: "valid-input-format-json",
|
||||
cfgFactory: func() (*config.Config, error) {
|
||||
cfg, _ := testutil.InitConfig(t)
|
||||
return cfg, nil
|
||||
},
|
||||
checkFlags: checkexpiration.CheckFlags{
|
||||
Threshold: 5000,
|
||||
FormatType: "json",
|
||||
Kubeconfig: "",
|
||||
},
|
||||
testErr: testNotImplementedErr,
|
||||
},
|
||||
{
|
||||
testCaseName: "valid-input-format-yaml",
|
||||
cfgFactory: func() (*config.Config, error) {
|
||||
cfg, _ := testutil.InitConfig(t)
|
||||
return cfg, nil
|
||||
},
|
||||
checkFlags: checkexpiration.CheckFlags{
|
||||
Threshold: 5000,
|
||||
FormatType: "yaml",
|
||||
},
|
||||
testErr: testNotImplementedErr,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.testCaseName, func(t *testing.T) {
|
||||
var objects []runtime.Object
|
||||
// TODO (guhan) append a dummy object for testing
|
||||
ra := fake.WithTypedObjects(objects...)
|
||||
|
||||
command := checkexpiration.CheckCommand{
|
||||
Options: tt.checkFlags,
|
||||
CfgFactory: tt.cfgFactory,
|
||||
ClientFactory: func(_ string, _ string) (client.Interface, error) {
|
||||
return fake.NewClient(ra), nil
|
||||
},
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err := command.RunE(&buffer)
|
||||
|
||||
if tt.testErr != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.testErr)
|
||||
}
|
||||
// TODO (guhan) add else part to check the actual vs expected o/p
|
||||
})
|
||||
}
|
||||
}
|
26
pkg/cluster/checkexpiration/errors.go
Normal file
26
pkg/cluster/checkexpiration/errors.go
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package checkexpiration
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ErrInvalidFormat is called when the user provides format other than yaml/json
|
||||
type ErrInvalidFormat struct {
|
||||
RequestedFormat string
|
||||
}
|
||||
|
||||
func (e ErrInvalidFormat) Error() string {
|
||||
return fmt.Sprintf("invalid output format specified %s. Allowed values are json|yaml", e.RequestedFormat)
|
||||
}
|
Loading…
Reference in New Issue
Block a user