From ff6f716159adff0f31c9d0954e4a5b5ec073ca89 Mon Sep 17 00:00:00 2001 From: Martin Guibert Date: Mon, 2 Aug 2021 17:01:01 +0200 Subject: [PATCH] update documentation for contributor to be able to add new resources / provider --- docs/README.md | 1 + docs/media/generalflow.png | Bin 0 -> 46926 bytes docs/media/generalflow.puml | 26 ++ docs/media/resource.png | Bin 31981 -> 48600 bytes docs/media/resource.puml | 28 +- docs/new-remote-provider.md | 161 ++++++++++ docs/new-resource.md | 280 +++++++++++------- .../aws/cloudfront_distribution_enumerator.go | 1 - pkg/remote/aws/init.go | 1 - 9 files changed, 378 insertions(+), 120 deletions(-) create mode 100644 docs/media/generalflow.png create mode 100644 docs/media/generalflow.puml create mode 100644 docs/new-remote-provider.md diff --git a/docs/README.md b/docs/README.md index 74bc5835..1f312411 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,6 +2,7 @@ This directory contains some documentation about the driftctl codebase, aimed at readers who are interested in making code contributions. +- [Add new remote provider](new-remote-provider.md) - [Add new resources](new-resource.md) - [Testing](testing.md) diff --git a/docs/media/generalflow.png b/docs/media/generalflow.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e31ec72ce43d73ad9137313116aab3e8064c92 GIT binary patch literal 46926 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

&4mhr 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 IACSupplier: Resource() +IACSupplier --> Driftctl: stateResources []Resource +Driftctl -> RemoteSupplier: Resource() +RemoteSupplier --> Driftctl: remoteResources []Resource + +hnote across: Run Middlewares +Driftctl --> Driftctl: List Middlewares +loop on every middleware +Driftctl -> Middleware: Execute(remoteResources, stateResources) +Middleware --> Driftctl: remoteResources, stateResources []Resource +end + +hnote across: Run Filters +Driftctl -> FilterEngine: Run(remoteResources) +FilterEngine --> Driftctl: remoteResources []Resource +Driftctl -> FilterEngine: Run(stateResources) +FilterEngine --> Driftctl: stateResources []Resource + +hnote across: Analyze +Driftctl -> Analyzer: Analyze(remoteResources, stateResources) +Analyzer --> Driftctl: Analyze + + +@enduml diff --git a/docs/media/resource.png b/docs/media/resource.png index 1514ff569f950731ac9c04ee7b956cccc4e81c02..a536cbb38006f06a5b6d8bbfae66577aad210f88 100644 GIT binary patch literal 48600 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 aH0SuLSdECQ$X*A5Nu?#^#gormb@^YJ4F)>^ literal 31981 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 Scanner: Resource() -Scanner -> Scanner: List Suppliers +Scanner -> Scanner: List Enumerators loop -Scanner -> Supplier: Resources() -Supplier -> RemoteSDK: List resource -RemoteSDK --> Supplier: []ResourcesIds -loop -Supplier -> TerraformProvider: ReadResource() -TerraformProvider --> Supplier: CTYRessource -Supplier -> CTYDeserializer: Deserialize() -CTYDeserializer --> Supplier: Resource +Scanner -> Enumerator: Enumerate() +Enumerator -> RemoteSDK: List resource +RemoteSDK --> Enumerator: []remoteRes +loop optionaly retrive resource needed attributes +Enumerator -> RemoteSDK: Retreive needed\nattributes +RemoteSDK --> Enumerator: Attrs +end +Enumerator --> Scanner: []Resources with\nlimited attributes +loop if deepmode +Scanner -> DetailsFetcher: ReadDetails(res) +DetailsFetcher -> TerraformProvider: ReadResource() +TerraformProvider --> DetailsFetcher: CTYValue +DetailsFetcher -> Deserializer: Deserialize() +Deserializer -> DetailsFetcher: Resource +DetailsFetcher -> Scanner: Resource with\nfull attributes end -Supplier --> Scanner: []Resource end Scanner --> Driftctl: []Resource -@enduml \ No newline at end of file +@enduml diff --git a/docs/new-remote-provider.md b/docs/new-remote-provider.md new file mode 100644 index 00000000..fb239298 --- /dev/null +++ b/docs/new-remote-provider.md @@ -0,0 +1,161 @@ +# Add a new remote provider + +A remote provider in Driftctl is a cloud provider like AWS, Github, GCP or Azure. +Current architecture allows to add a new provider in a few step. + +## Declaring the new remote provider +First you need to create a new directory in `pkg/remote/`. It will sit next to already implemented one like `pkg/remote/aws`. + +Inside this directory you will create a `init.go`. First thing to do will be to define the remote name constant: +```go +const RemoteAWSTerraform = "aws+tf" +``` + +You will then create a function to init the provider and all the future resource enumerator. Best way to do would be to copy the function signature from an other provider: +```go +func Init( + // Version required by the user + version string, + // Util to send alert + alerter *alerter.Alerter, + // Library that contains all providers + providerLibrary *terraform.ProviderLibrary, + // Library that contains the enumerators and details fetcher for each supported resources + remoteLibrary *common.RemoteLibrary, + // progress display + progress output.Progress, + // Repository for all resource schema + resourceSchemaRepository *resource.SchemaRepository, + // Factory used to create driftctl resource + factory resource.ResourceFactory, + // Drifctl config directory (in which terraform provider is downloaded) + configDir string) error { + + // Define the default version of terraform provider to be used. When the user does not require a specific one + if version == "" { + version = "3.19.0" + } + + // This is this actual terraform provider creation + provider, err := NewAWSTerraformProvider(version, progress, configDir) + if err != nil { + return err + } + // And then initialisation + err = provider.Init() + if err != nil { + return err + } + + // You'll need to create a new cache that will be use to cache fetched resources lists + repositoryCache := cache.New(100) + + // Deserializer is used to convert cty value return by terraform provider to driftctl AbstactResource + deserializer := resource.NewDeserializer(factory) + + // Adding the provider to the library + providerLibrary.AddProvider(terraform.AWS, provider) +} +``` + +When it's done you'll create a `provider.go` file to contains your terraform provider representation. Again you should looks at other implementation : +```go +// Define your actual provider representation, It is required to compose with terraform.TerraformProvider and to have a name and a version +// Please note that the name should match the real terraform provider name. +type AWSTerraformProvider struct { + *terraform.TerraformProvider + session *session.Session + name string + version string +} + +func NewAWSTerraformProvider(version string, progress output.Progress, configDir string) (*AWSTerraformProvider, error) { + // Just pass your version and name + p := &AWSTerraformProvider{ + version: version, + name: "aws", + } + // Use terraformproviderinstaller to retreive the provider if needed + installer, err := tf.NewProviderInstaller(tf.ProviderConfig{ + Key: p.name, + Version: version, + ConfigDir: configDir, + }) + if err != nil { + return nil, err + } + p.session = session.Must(session.NewSessionWithOptions(session.Options{ + SharedConfigState: session.SharedConfigEnable, + })) + + // Config is dependant on the teraform provider needs. + tfProvider, err := terraform.NewTerraformProvider(installer, terraform.TerraformProviderConfig{ + Name: p.name, + DefaultAlias: *p.session.Config.Region, + GetProviderConfig: func(alias string) interface{} { + return awsConfig{ + Region: alias, + MaxRetries: 10, + } + }, + }, progress) + if err != nil { + return nil, err + } + p.TerraformProvider = tfProvider + return p, err +} + +func (a *AWSTerraformProvider) Name() string { + return a.name +} + +func (p *AWSTerraformProvider) Version() string { + return p.version +} +``` + +You are now almost done. You'll need to make driftctl aware of this provider so in `pkg/remote/remote.go` add your new constant in `supportedRemotes`: +```go +var supportedRemotes = []string{ + aws.RemoteAWSTerraform, + github.RemoteGithubTerraform, +} +``` +And don't forget to modify the Activate function to be able to activate your new provider. You'll need to add a new case in the switch: +```go +func Activate(remote, version string, alerter *alerter.Alerter, + providerLibrary *terraform.ProviderLibrary, + remoteLibrary *common.RemoteLibrary, + progress output.Progress, + resourceSchemaRepository *resource.SchemaRepository, + factory resource.ResourceFactory, + configDir string) error { + switch remote { + case aws.RemoteAWSTerraform: + return aws.Init(version, alerter, providerLibrary, remoteLibrary, progress, resourceSchemaRepository, factory, configDir) + case github.RemoteGithubTerraform: + return github.Init(version, alerter, providerLibrary, remoteLibrary, progress, resourceSchemaRepository, factory, configDir) + default: + return errors.Errorf("unsupported remote '%s'", remote) + } +} +``` + +Your provider is now set up ! + +## Prepare Driftctl to support new resources + +New resource for the just added provider will be located in `pkg/resource/`. You should create this directory and the `metadata.go` file. +Inside this file add a new function: +```go +func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) { +} +``` + +And add a call to it in the `remote//init.go` you created at first step. + +Last step will add to create test for the new resource you will implement. +Please use TestCreateNewSchema located in `test/schemas/schemas_test.go` to generate a schema file that will be used for the mocked provider. + +Everything is not ready, you should [start adding new resources](new-resource.md) ! diff --git a/docs/new-resource.md b/docs/new-resource.md index f03967a3..6148d826 100644 --- a/docs/new-resource.md +++ b/docs/new-resource.md @@ -1,149 +1,215 @@ # Add new resources +First you need to understand how driftctl scan works. Here you'll find a global overview of the step that compose the scan: + +![Diagram](media/generalflow.png) + +And here you'll see a more detailed flow of the retrieving resource sequence: ![Diagram](media/resource.png) ## Defining the resource -First step is to implement a new resource. To do that you need to define a go struct representing all fields that need to be monitored for this kind of resource. - -You can find several examples in already implemented resources like aws.S3Bucket: +First step would be to add a file under `pkg/resource//resourcetype.go`. +This file will define a const string that will be the resource type identifier in driftctl. +Optionally, if your resource is to be supported by driftctl experimental deep mode, you can add a function that will be +applied to this resource when it's created. This allows to prevent useless diff to be displayed. +You can also add some metadata to fields so they are compared or displayed differently. +For example this defines the aws_iam_role resource : ```go -type AwsS3Bucket struct { - AccelerationStatus *string `cty:"acceleration_status"` - Acl *string `cty:"acl" diff:"-"` - Arn *string `cty:"arn"` - Bucket *string `cty:"bucket"` -... -``` +const AwsIamRoleResourceType = "aws_iam_role" -Your new type will need to implement `resource.Resource` interface in order for driftctl to retrieve its type and a unique identifier for it. - -```go -type Resource interface { - TerraformId() string - TerraformType() string +func initAwsIAMRoleMetaData(resourceSchemaRepository resource.SchemaRepositoryInterface) { + // assume_role_policy drifts will be displayed as json + resourceSchemaRepository.UpdateSchema(AwsIamRoleResourceType, map[string]func(attributeSchema *resource.AttributeSchema){ + "assume_role_policy": func(attributeSchema *resource.AttributeSchema) { + attributeSchema.JsonString = true + }, + }) + // force_detach_policies should not be compared so it will be removed before the comparison + resourceSchemaRepository.SetNormalizeFunc(AwsIamRoleResourceType, func(res *resource.AbstractResource) { + val := res.Attrs + val.SafeDelete([]string{"force_detach_policies"}) + }) } ``` -Some resources are read differently by the terraform state reader and the supplier. You can optionally implement `resource.NormalizedResource` to add a normalization step before the comparison is made. - +When it's done you'll have to add this function to the metadata initialisation located in `pkg/resource//metadatas.go` : ```go -type NormalizedResource interface { - NormalizeForState() (Resource, error) - NormalizeForProvider() (Resource, error) +func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) { + initAwsAmiMetaData(resourceSchemaRepository) } ``` -For example S3Bucket policy is encoded in json but the formatting (newline and tabs) differs when read using the state reader. S3Bucket implements `resource.NormalizedResource`: - +In order for you new resource to be supported by our terraform state reader you should add it in `pkg/resource/resource_types.go` inside the `supportedTypes` slice. ```go -func (s S3Bucket) NormalizeForState() (resource.Resource, error) { - err := normalizePolicy(&s) - return &s, err -} - -func (s S3Bucket) NormalizeForProvider() (resource.Resource, error) { - err := normalizePolicy(&s) - return &s, err -} - -func normalizePolicy(s *S3Bucket) error { - if s.Policy.Policy != nil { - jsonString, err := structure.NormalizeJsonString(*s.Policy.Policy) - if err != nil { - return err - } - s.Policy.Policy = &jsonString - } - return nil +var supportedTypes = map[string]struct{}{ + "aws_ami": {}, } ``` -You can implement different normalization for the state representation and the supplier one. -## Supplier and Deserializer +All resources inside driftctl are `resource.AbstractResource` except for some unit tests. This struct has an id and a type, +All the other attributes are represented inside a `map[string]interface` + +## Repository, Enumerator and DetailsFetcher Then you will have to implement two interfaces: -- `resource.supplier` is used to read resources list. It will call the cloud provider SDK to get the list of resources, and - the terraform provider to get the details for each of these resources -- `remote.CTYDeserializer` is used to transform terraform cty output into your resource +- Repositories are the way we decided to hide direct calls to sdk and pagination logic. It's a common pattern. +- `remote.comon.Enumerator` is used to read resources list. It will call the cloud provider SDK to get the list of resources. + For some resource it could make other call to enrich the resource with needed field when driftctl is used in non deep mode +- `remote.comon.DetailsFetcher` is used to make a call to terraform provider read resource. + This implementation is optional and is only needed if your resource type is to be supported by experimental deep mode. + Please also note that it exists a generic implementation as `remote.comon.GenericDetailsFetcher` that can be used with most resource type. -### Supplier -This is used to read resources list. It will call the cloud provider SDK to get the list of resources, and the -terraform provider to get the details for each of these resources. -You can use an already implemented resource as example. +### Repository + +This will be the struct that hide all the logic linked to your provider sdk. All provider have different way to implement pagination or to name function in their api. +Here we will name all listing function `ListAll` and they all return `[]Resource`. + +For aws we decided to split repositories using the amazon logic. So you'll find repositories for EC2, S3 and so on. +Some provider does not have this grouping logic. Keep in mind that like all our file/struct repositories should not be too big. +So it might be useful to create a grouping logic. + +For our Github implementation the number of listing function was not that heavy so we created a unique repository for everything: + +```go +type GithubRepository interface { + ListRepositories() ([]string, error) + ListTeams() ([]Team, error) + ListMembership() ([]string, error) + ListTeamMemberships() ([]string, error) + ListBranchProtection() ([]string, error) +} + +type githubRepository struct { + client GithubGraphQLClient + ctx context.Context + config githubConfig + cache cache.Cache +} + +func NewGithubRepository(config githubConfig, c cache.Cache) *githubRepository { + ctx := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: config.Token}, + ) + oauthClient := oauth2.NewClient(ctx, ts) + + repo := &githubRepository{ + client: githubv4.NewClient(oauthClient), + ctx: context.Background(), + config: config, + cache: c, + } + + return repo +} +``` + +So as you can see this contains the logic to create the github client (it might be created outside the repository if it +makes sense to share it between multiple repositories). It also get a cache so every request is cached. +Driftctl sometimes needs to retrieve list of resources more than once, so we cache every request to avoid unnecessary call. + +### Enumerator + +This is used to read resources list. Enumerator is found in `pkg/remote//_enumerator.go`. It will call the cloud provider SDK to get the list of resources. + +Note that at this point resources should not be entirely fetched. +Most of the resource returned by enumerator have empty attributes: they only represent type and terraform id. +There are exception to this: +- Sometime, you will need some more information about resources to retrieve them using the provider they should be added to the resource attribute maps. +- For some more complex cases, middleware needs more information that the id and type and in order to make classic run of driftctl coherent with a run with deep mode activated, +these informations should be fetched manually by the enumerator using the remote sdk. + + +Note that we use the classic repository to hide calls to the provider sdk. +You will probably need to at least add a listing function to list you new resource. + +You should use an already implemented Enumerator as example. + +For example when implementing ec2_instance resource you will need to add a ListAllInstances() function to `repository.EC2Repository`. +It will be called by the enumerator to retrieve the instances list. + Supplier constructor could use these arguments: +- an instance of `Repository` that you will use to retrieved information about the resource +- the global resource factory that should always be used to create a new `resource.Resource` + +Enumerator then need to implement: +- `SupportedType() resource.ResourceType` that will return the constant you defined in the type file at first step +- `Enumerate() ([]resource.Resource, error)` that will return the resource listing. Note that at this point resources should not be entirely fetched. +Most of the resource returned by enumerator have empty attributes: they only represent the type, and the terraform id. -- an instance of `ParallelRunner` that you will use to parallelize your call to the supplier: ```go -results := make(map[string][]cty.Value) -for _, bucket := range response.Buckets { - b := *bucket - s.runner.Run(func() error { - return s.readBucket(b, results) - }) +type EC2InstanceEnumerator struct { + repository repository.EC2Repository + factory resource.ResourceFactory } -if err := s.runner.Wait(); err != nil { - return nil, err -} -``` -- an instance of `terraform.ResourceReader` that you can use to read resource using the supplier: - -```go -s3Bucket, err := s.reader.ReadResource(aws.AwsS3BucketResourceType, name) -if err != nil { - logrus.Warnf("Error reading bucket %s[%s]: %+v", name, aws.AwsS3BucketResourceType, err) - return err -} -appendValueIntoMap(results, aws.AwsS3BucketResourceType, s3Bucket) -``` - -- an instance of the cloud provider SDK that you will use to retrieve resources list - -### Deserializer - -The deserializer is used when reading resource from the terraform provider or from the state. -The interface contains a `Deserialize(values []cty.Value) ([]resource.Resource, error)` method that you'll implement. - -You should then deserialize the obtained cty values into your resource and return the list. - -Example: [aws_s3_bucket_deserializer.go](https://github.com/cloudskiff/driftctl/blob/main/pkg/resource/aws/deserializer/s3_bucket_deserializer.go) - -## Adding your resource - -There are two files you are going to edit to make driftctl aware of your new resource. - -For the state reader you will need to add your `CTYDeserializer` implementation into `iac/deserializers.go`. -Just add an instance in the list: - -```go -func Deserializers() []remote.CTYDeserializer { - return []remote.CTYDeserializer{ - aws.NewS3BucketDeserializer(), - ... +func NewEC2InstanceEnumerator(repo repository.EC2Repository, factory resource.ResourceFactory) *EC2InstanceEnumerator { + return &EC2InstanceEnumerator{ + repository: repo, + factory: factory, } } -``` -Then in the cloud provider's init file (e.g. in `remote/aws/init.go`), add your new implementation for `resource.Supplier`: +func (e *EC2InstanceEnumerator) SupportedType() resource.ResourceType { + return aws.AwsInstanceResourceType +} -```go -func Init() error { - provider, err := NewTerraFormProvider() +func (e *EC2InstanceEnumerator) Enumerate() ([]resource.Resource, error) { + instances, err := e.repository.ListAllInstances() if err != nil { - return err + return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType())) } - terraform.AddProvider(terraform.AWS, provider) - resource.AddSupplier(NewS3BucketSupplier(provider.Runner().SubRunner(), s3.New(provider.session))) - ... + results := make([]resource.Resource, len(instances)) + + for _, instance := range instances { + results = append( + results, + e.factory.CreateAbstractResource( + string(e.SupportedType()), + *instance.InstanceId, + map[string]interface{}{}, + ), + ) + } + + return results, err } ``` +As you can see, listing error are treated in a particular way. Instead of failing and stopping the scan they will be handled, and an alert will be created. +So please don't forget to wrap these errors inside a NewResourceListingError. +For some provider error handling is not that coherent, so you might need to check in `pkg/remote/resource_enumeration_error_handler.go` and add a new case for your error. -Don't forget to add unit tests after adding a new resource. -You can also add acceptance tests if you think it makes sense. + +Once the enumerator is written you have to add it to the remote init located in `pkg/remote//init.go` : +```go + s3Repository := repository.NewS3Repository(client.NewAWSClientFactory(provider.session), repositoryCache) + remoteLibrary.AddEnumerator(NewS3BucketEnumerator(s3Repository, factory, provider.Config)) +``` + +### DetailsFetcher + +DetailsFetcher are only used by driftctl experimental deep mode. + +This is the component that call terraform provider to retrieve the full attribute for each resource. +We do not want to reimplement what has already been done in every terraform provider, so you should not call the remote sdk to do this. + +If `common.GenericDetailsFetcher` satisfy your needs you should always prefer using it instead of implementing DetailsFetcher in a new struct. + +The DetailsFetcher should also be added to `pkg/remote//init.go` even if you use the generic version : +```go + remoteLibrary.AddDetailsFetcher(aws.AwsEbsVolumeResourceType, common.NewGenericDetailsFetcher(aws.AwsEbsVolumeResourceType, provider, deserializer)) +``` + + +***Don't forget to add unit tests after adding a new resource.*** + +You can also find example of "integration" tests in pkg/remote/_scanner_test.go + +You should also add acceptance tests if you think it makes sense, they are located next to the resource definition described at first step. diff --git a/pkg/remote/aws/cloudfront_distribution_enumerator.go b/pkg/remote/aws/cloudfront_distribution_enumerator.go index e66d5df5..60f8cc84 100644 --- a/pkg/remote/aws/cloudfront_distribution_enumerator.go +++ b/pkg/remote/aws/cloudfront_distribution_enumerator.go @@ -41,6 +41,5 @@ func (e *CloudfrontDistributionEnumerator) Enumerate() ([]*resource.Resource, er ), ) } - return results, err } diff --git a/pkg/remote/aws/init.go b/pkg/remote/aws/init.go index e38bc597..90d28350 100644 --- a/pkg/remote/aws/init.go +++ b/pkg/remote/aws/init.go @@ -36,7 +36,6 @@ func Init(version string, alerter *alerter.Alerter, if err != nil { return err } - repositoryCache := cache.New(100) s3Repository := repository.NewS3Repository(client.NewAWSClientFactory(provider.session), repositoryCache)