Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yet Another FileAdapter: Google Cloud Storage #708

Merged
merged 10 commits into from
Mar 8, 2016
Merged

Yet Another FileAdapter: Google Cloud Storage #708

merged 10 commits into from
Mar 8, 2016

Conversation

asciimike
Copy link
Contributor

Tossing my hat in the ring for building another FileAdapter, this time GCSAdapter.js for integrating Google Cloud Storage

Like all the other file adapters, you can create one like so:

var GCSAdapter = require('parse-server').GCSAdapter;
...
var api = new ParseServer({
  ...
  filesAdapter: new GCSAdapter(
    "<gcp_project_id>",
    "<path/to/keyfile>",
    "<gcp_bucket_name>",
    {
      bucketPrefix: <String>,
      directAccess: <Boolean>
    }
  )
});

Re: #545 I'm happy to wait on a redesign if that's where we're going. Agree that it's a bit hard to handle these currently, and the dependencies on AWS, Azure, and GCP Node modules is getting a little ridiculous...

On the subject of unit tests--I went ahead and modified helpers.js locally to point to GCS and tested these locally, with 21/21 passing. I also created and added a ParseFile+GCS.spec.js, which contains tests for Parse Server proxied files as well as public readable files. Note that these tests require a GCP Project, keyfile, and GCS Bucket.

I'm putting some thought into mocking out the various providers to avoid all the issues with having sets of keys for each service, as I'm sure the team doesn't want to maintain a bunch of various keys to various cloud platforms. I also have some thoughts on creating cloud provider config settings to encapsulate the AWS, Azure, GCP, etc. keys that I'd be happy to talk to someone about.

@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@asciimike
Copy link
Contributor Author

Still plagued by the flaky Geopoint test in #572 , but other tests will work.

Also, if people are annoyed by the fact that the tests still show up (and are just listed as pending), I thought of two quick solutions:

  1. Create a spec/optional directory, which is excluded from the jasmine.json spec_files glob. This would require no changes to the present jasmine.json, since directories aren't recursed into currently.
  2. Change the glob to !(*+*).spec.js which ignores any foo+bar.spec.js, meaning that any "extension" specs such as GCS, S3, etc. would take the form of test+extension.spec.js and would thus be ignored unless a developer explicitly calls npm test spec/test+extension.spec.js.

Either solution here allows us to get rid of 3e41a21 since the tests wouldn't be run unless a developer explicitly wanted to run it.

Also, I'd love to be able to contribute to the Wiki to clean up some of the Files docs: basically just add a section for each provider, as well as an overview of what's going on. What's the best way to contribute back to the Wiki (given how PRs against it aren't straightforward)?

@flovilmart
Copy link
Contributor

@mcdonamp we were discussing @nlutsenko test factories for those adapter. Those factories would allow you to keep the adapter on your repo, and use travis with your encrypted keys. this way we'll ensure the compatibility with parse-server without burdening the core repository with zillions of implementations. What do you think?

@otymartin
Copy link

@mcdonamp Hey - parse newbie talking. What does this mean? I deployed parse server to google app engine using mongolab. Does that mean I can use google datastore as an alternative to mongolab using this adapter? Preferably, I'd like to do that to keep all my backend activity within a single platform.

@flovilmart
Copy link
Contributor

@otymartin it means you can use Google Cloud Storage, to store and serve the PFFiles instead of the default GridFS or Amazon S3. For Now, you cant use GCP NoSQL database engine as some more changes are required to this project.
You can still host your database on GCP, but you would have to manage it manually.

@asciimike
Copy link
Contributor Author

@otymartin @flovilmart beat me to the punch by seconds! As he said, this means that you can store your Parse Files (user generated content like images, videos, audio, etc.) in Google Cloud Storage, Google's Petabyte static storage system. This is distinct from something like Cloud Datastore, which is Google's Hosted NoSQL offering. Currently Parse Server is very mongo specific and making it fully database agnostic is going to take a lot of time, though #698 is a good step in that direction.

@asciimike
Copy link
Contributor Author

@flovilmart totally agree with this idea, though I've got some concerns that it'll raise the barrier to entry for creating such extensions, especially for new devs. Maybe creating a Parse Server Extension repo with a template (basically the helpers.js and jasmine.json) that folks can clone and easily add to. The other concern I have is discoverability, though I assume that could be taken care of relatively easily on the wiki (by adding an extensions page) or by the individual cloud providers who curate their extensions.

What can I do to help this move forward? Some potential AIs I see here are:

  1. Reconfigure this adapter as a separate node module
  2. Rip out all provider specific code and packages

FWIW, if folks don't care about running their own, I'd probably be OK owning a parse-server-file-extensions module that bundles the adapters for S3, Azure, and GCS as well as handles testing, etc. Thus the imports end up looking like:

var S3Adapter = require('parse-server-file-extensions').S3Adapter(config);
var AzureBlobAdapter = require('parse-server-file-extensions').AzureBlobAdapter(config);
var GCSAdapter = require('parse-server-file-extensions').GCSAdapter(config);

This might also make config a little easier, since we could try to offer a single shared config file for all these (though TBH, not sure why anyone would be using multiple file storage providers).

@flovilmart
Copy link
Contributor

We're having pretty intense discussions around that. My main concern is testability and stability.
those providers require API keys, and we can't afford to have jasmine ignores all the way in the repo for those adapter.

I'm refactoring the FIlesController tests now into a factory, and I uncovered 3 major issues with S3Adapter as it's completely untested.

The test factories are design to be easy to use:

var TestsFactory = require("./FilesControllerTestsFactory");


// Small additional tests to improve overall coverage
describe("FilesController",()=>{
  TestsFactory(new GridStoreAdapter());
  if (process.env.S3_ACCESS_KEY && process.env.S3_SECRET_KEY) {
     TestsFactory(new S3Adapter(process.env.S3_ACCESS_KEY, process.env.S3_SECRET_KEY, 'parse.server.tests')); 
  } else {
    console.warn("cannot test S3Adapter");
  }
});
``` 

@asciimike
Copy link
Contributor Author

Cool--I figured, as I'm sure it's a contentious issue. Happy to weigh in if you'd like another opinion; otherwise, happy to stay out as I'm sure there are already plenty of folks more knowledgeable than me working to solve it.

I found a few issues with mine that were teased out in testing, so luckily I fixed them before they saw the light of day.

I thought about switching off the presence of env variables as an option as well, not sure why I didn't put it down... I'm a fan of this strategy, as well as of splitting these tests (and the adapters) out into a separate repo.

Not sure if the best strategy is to merge all of these adapters in and then cut them all out at the same time and provide a major version bump, or just herd cats to pull the appropriate PRs somewhere else. Either way, let me know what you need in the way of help this moving forward!

@asciimike
Copy link
Contributor Author

@flovilmart I assume we're waiting on #718 to align these and then merge?

I'm happy to open an issue on the topic of File Adapter refactoring, potentially to a separate repo, if that will provide a place for us to consolidate our thoughts and gather broader community feedback.

@flovilmart
Copy link
Contributor

@mcdonamp waiting for #738 as it has just the test factories for the FileAdapters. I managed to get the testing going for external adapter for the push adapter in https://github.com/flovilmart/parse-server-urban-airship. That involves a submodule and weird stuff.

The debate is open on the question of whether we should add those adapters in the core repo or not :)

…into mcdonald-gcs-adapter

Get GCSAdapter up to snuff with FilesController + FilesControllerTestFactory

* 'master' of https://github.com/ParsePlatform/parse-server: (102 commits)
  Remove duplicated instructions
  Release and Changelog for 2.1.4
  fixes missing coverage with sh script
  Fix update system schema
  Adds optional COVERAGE
  Allows to pass no where in $select clause
  Sanitize objectId in
  Fix delete schema when actual collection does not exist
  Fix replace query overwrite the existing query object.
  Fix create system class with relation/pointer
  Use throws syntax for errors in SchemasRouter.
  Completely migrate SchemasRouter to new MongoCollection API.
  Add tests that verify installationId in Cloud Code triggers.
  Propagate installationId in all Cloud Code triggers.
  Add test
  expiresAt should be a Date, not a string. Fixes #776
  Fix missing 'let/var' in OneSignalPushAdapter.spec.
  Don't run any afterSave hooks if none are registered.
  Fix : remove query count limit
  Flatten custom operations in request.object in afterSave hooks.
  ...
@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@asciimike
Copy link
Contributor Author

@flovilmart ok, got this back in line with the other adapters and the new stuff in FilesController (which is nice stuff--super slick!). Everything should be good to go here, tests pass (plus my other tests, which I have removed in favor of the FilesController).

Also, of note: I chose not to implement createBucket(). Generally I don't like create lots of buckets without the user fully realizing, as I think that a dev should know exactly what bucket they're writing to (especially since they're paying for it--one have to go to a console somewhere and enter a credit card, creating a bucket shouldn't be too difficult after that). Secondly, I think that the createBucket() calls on deleteFile() and getFileData() are extraneous. If the bucket doesn't exist and is automatically created, immediately calling delete or get isn't going to do anything, as the file can't exist (unless there's some fantastic race condition going on that somehow ends up uploading a file in between the create request and the subsequent request).

@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@flovilmart
Copy link
Contributor

@mcdonamp no problem! You need a rebase and I believe we're good to go!

@asciimike
Copy link
Contributor Author

Ok, I think I may update to what's in #833 to get the proper loading from the environment, then I'll run another quick set of tests and get it in.

…into mcdonald-gcs-adapter

* 'master' of https://github.com/ParsePlatform/parse-server:
  Remove limit when counting results.
  beforeSave changes should propagate to the response
  Fix delete relation field when _Join collection not exist
  Test empty authData block on login for #413
  Fix for related query on non-existing column
  Fix Markdown format: make checkboxes visible
  Fix create wrong _Session for Facebook login
  Modified the npm dev script to support Windows
  Improves tests, ensure unicity of roleIds
  Fix reversed roles lookup
  Fix leak warnings in tests, use mongodb-runner from node_modules
  Improves documentation, add loading tests
  Improves loading of Push Adapter, fix loading of S3Adapter
  Adds public_html and views for packaging
  Removes shebang for windows
  Better support for windows builds
  Fix add field to system schema
  Convert Schema.js to ES6 class.
@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@codecov-io
Copy link

Current coverage is 90.10%

Merging #708 into master will decrease coverage by -1.62% as of 03ae193

@@            master   #708   diff @@
=====================================
  Files           71     72     +1
  Stmts         4108   4164    +56
  Branches       849    863    +14
  Methods          0      0       
=====================================
- Hit           3768   3752    -16
  Partial         10     10       
- Missed         330    402    +72

Review entire Coverage Diff as of 03ae193

Powered by Codecov. Updated on successful CI builds.

@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@facebook-github-bot
Copy link

@mcdonamp updated the pull request.

@asciimike
Copy link
Contributor Author

@flovilmart ok, this should be good to go. Lots of whitespace changes (looks like my sublime config likes that ;)

Also updated the README for both, and all tests are passing. Thanks for all the hard work and guidance here. I'm also happy to help the folks working on #545 and #716 if they need to know next steps.

@@ -149,6 +154,19 @@ S3_DIRECT_ACCESS

```

###### Configuring `GCSAdapter`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great you added those too!

flovilmart added a commit that referenced this pull request Mar 8, 2016
Yet Another FileAdapter: Google Cloud Storage
@flovilmart flovilmart merged commit 8086974 into parse-community:master Mar 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants