GCP setMetadata startup script to instance on Creation - php

I'm trying to create instance assign an IP and set a startup script, I managed to create the instance and assign IP to it but I have no idea how to add startup script.
Here is my Code Please help :
namespace Google\Cloud\Samples\Compute;
require_once 'vendor/autoload.php';
use Google\Cloud\Compute\V1\InstancesClient;
use Google\Cloud\Compute\V1\AttachedDisk;
use Google\Cloud\Compute\V1\AttachedDiskInitializeParams;
use Google\Cloud\Compute\V1\Instance;
use Google\Cloud\Compute\V1\NetworkInterface;
use Google\Cloud\Compute\V1\Operation;
use Google\Cloud\Compute\V1\ZoneOperationsClient;
use Google\Cloud\Compute\V1\AccessConfig;
use Google\Cloud\Compute\V1\Items;
use Google\Cloud\Compute\V1\Metadata;
function create_instance() {
$projectId = 'impactful-name-324714';
$zone = 'us-central1-c';
$instanceName = 'test1-micro';
$machineType = 'e2-micro';
$sourceImage = 'projects/centos-cloud/global/images/family/centos-7';
$networkName = 'global/networks/default';
$networkTier = 'PREMIUM';
// Set the machine type using the specified zone.
$machineTypeFullName = sprintf('zones/%s/machineTypes/%s', $zone, $machineType);
// Describe the source image of the boot disk to attach to the instance.
$diskInitializeParams = (new AttachedDiskInitializeParams())
->setSourceImage($sourceImage);
$disk = (new AttachedDisk())
->setBoot(true)
->setInitializeParams($diskInitializeParams);
// Use the network interface provided in the $networkName argument.
$accessConfig = (new AccessConfig())
->setName('PREMIUM');
$network = (new NetworkInterface())
->setAccessConfigs([$accessConfig]);
// Create the Instance object.
$instance = (new Instance())
->setName($instanceName)
->setDisks([$disk])
->setMachineType($machineTypeFullName)
->setNetworkInterfaces([$network])
->setMetadata([$metaData]);
// Insert the new Compute Engine instance using InstancesClient.
$instancesClient = new InstancesClient();
$operation = $instancesClient->insert($instance, $projectId, $zone);
// Wait for the create operation to complete.
if ($operation->getStatus() === Operation\Status::RUNNING) {
$operationClient = new ZoneOperationsClient();
$operationClient->wait($operation->getName(), $projectId, $zone);
}
printf('Created instance %s' . PHP_EOL, $instanceName);
}
putenv('GOOGLE_APPLICATION_CREDENTIALS=keyfile.json');
create_instance();
I tried adding This :
$metaItems = (new Items())
->setKey('startup-script')
->setValue('#_some_cmnd_I_want_to_exec_#');
$metaData = (new Metadata())
->setItems([$metaItems]);
but it didn't work, I know its messy maybe even bad written but i'm new to coding.
Used resources :
http://googleapis.github.io/google-cloud-php/#/docs/cloud-compute/v0.3.1/compute/readme
https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/compute

Alright I just figured it out i removed the "[" and "]"
from
$instance = (new Instance())
->setName($instanceName)
->setDisks([$disk])
->setMachineType($machineTypeFullName)
->setNetworkInterfaces([$network])
->setMetadata([$metaData]);
to
$instance = (new Instance())
->setName($instanceName)
->setDisks([$disk])
->setMachineType($machineTypeFullName)
->setNetworkInterfaces([$network])
->setMetadata($metaData);
Now it Works
the full code now :
namespace Google\Cloud\Samples\Compute;
require_once 'vendor/autoload.php';
use Google\Cloud\Compute\V1\InstancesClient;
use Google\Cloud\Compute\V1\AttachedDisk;
use Google\Cloud\Compute\V1\AttachedDiskInitializeParams;
use Google\Cloud\Compute\V1\Instance;
use Google\Cloud\Compute\V1\NetworkInterface;
use Google\Cloud\Compute\V1\Operation;
use Google\Cloud\Compute\V1\ZoneOperationsClient;
use Google\Cloud\Compute\V1\AccessConfig;
use Google\Cloud\Compute\V1\Items;
use Google\Cloud\Compute\V1\Metadata;
function create_instance() {
$projectId = 'impactful-name-324714';
$zone = 'us-central1-c';
$instanceName = 'test1-micro';
$machineType = 'e2-micro';
$sourceImage = 'projects/centos-cloud/global/images/family/centos-7';
$networkName = 'global/networks/default';
$networkTier = 'PREMIUM';
// Set the machine type using the specified zone.
$machineTypeFullName = sprintf('zones/%s/machineTypes/%s', $zone, $machineType);
// Describe the source image of the boot disk to attach to the instance.
$diskInitializeParams = (new AttachedDiskInitializeParams())
->setSourceImage($sourceImage);
$disk = (new AttachedDisk())
->setBoot(true)
->setInitializeParams($diskInitializeParams);
$metaItems = (new Items())
->setKey('startup-script')
->setValue('#_some_cmnd_I_want_to_exec_#');
$metaData = (new Metadata())
->setItems([$metaItems]);
// Use the network interface provided in the $networkName argument.
$accessConfig = (new AccessConfig())
->setName('PREMIUM');
$network = (new NetworkInterface())
->setAccessConfigs([$accessConfig]);
// Create the Instance object.
$instance = (new Instance())
->setName($instanceName)
->setDisks([$disk])
->setMachineType($machineTypeFullName)
->setNetworkInterfaces([$network])
->setMetadata($metaData);
// Insert the new Compute Engine instance using InstancesClient.
$instancesClient = new InstancesClient();
$operation = $instancesClient->insert($instance, $projectId, $zone);
// Wait for the create operation to complete.
if ($operation->getStatus() === Operation\Status::RUNNING) {
$operationClient = new ZoneOperationsClient();
$operationClient->wait($operation->getName(), $projectId, $zone);
}
printf('Created instance %s' . PHP_EOL, $instanceName);

Related

Firestore connection issue in Laravel

I am developing admin pannel on laravel with firebase database. It is working well with real time database but in case of firestore it gives error on collection().
classes I am importing are
use Illuminate\Http\Request;
use \Kreait\Firebase\Database;
use Kreait\Firebase\ServiceAccount;
use Kreait\Firebase\Factory;
use Google\Cloud\Firestore\FirestoreClient;
Here is code of realtime database which is working fine.
$factory = (new Factory)->withServiceAccount(__DIR__.'/errand.json');
$database = $factory->createDatabase();
$reference = $database->getReference('tokens');
$value = $reference->getValue();
but issue arises in firestore in collection() and its code is
$factory = (new Factory)->withServiceAccount(__DIR__.'/foodTruck.json');
$database =$factory->createFirestore();
$docRef = $database->collection('drivers');
$snapshot = $docRef->snapshot();
here is error thrown by laravel:
Error
Call to undefined method Kreait\Firebase\Factory::collection()
I also installed gRPC etc but not getting rid of this issue. Anyone please help me.
I've changed this code
$factory = (new Factory)->withServiceAccount(__DIR__.'/foodTruck.json');
$database =$factory->createFirestore();
$docRef = $database->collection('drivers');
$snapshot = $docRef->snapshot();
to this one
$factory = (new Factory)->withServiceAccount(__DIR__.'/mobznew.json');
$database = $factory->createFirestore()->database();
$usersRef = $database->collection('users');
$snapshot = $usersRef->documents();
foreach ($snapshot as $user) {
$age = array("uid"=>$user['userId'],"email"=>$user['email']);
$data[]=$age;
}
echo json_encode($data);
this worked fine for me. Special thanks to #Frankich

How can you use the ResourceWatcher bundle from YoSymfony?

I am trying to make a file watcher where, when you add, update or delete a file, you can see the files updates in a database. I'm using the framework Symfony4 and a bundle from it called ResourceWatcher from YoSymfony. This bundle uses the Finder bundle from Symfony to find files in the directories specified and then, the watcher compares the cache and the new file to see if there are any changes. When I use a method with the watcher which returns a path array, when I try to see the array, it returns null. How am I suppose to use these methods and their returns?
I put the var_dump everywhere to see that the problem comes from the findChanges()->getUpdatedFiles() and getNewFiles();
//OLD CODE
$finder = new Finder();
$finder->files()
->name('*.csv')
->in('%kernel.root_dir%/../src/data/');
//watcher
$hashContent = new Crc32ContentHash();
$resourceCache = new ResourceCachePhpFile('cache-key.php');
$watcher = new ResourceWatcher($resourceCache, $finder, $hashContent);
$watcher->initialize();
if($watcher->findChanges()->hasChanges()){
if($watcher->findChanges()->getNewFiles() === null){
$paths = $watcher->findChanges()->getUpdatedFiles();
}
else{
$paths = $watcher->findChanges()->getNewFiles();
}
$propertyAccessor = PropertyAccess::createPropertyAccessor();
var_dump($propertyAccessor->getValue($paths, '[first_name]'));
die();
}
I'd like to be able to see the paths, convert them into string and use that into my other method to make the data appear in my database.
In my var_dump, I get NULL in terminal.
EDIT:[first_name] is in my csv-file, you can dump $paths directly.
//NEW CODE
$finder = new Finder();
$finder->files()
->name('*.csv')
->in('%kernel.root_dir%/../src/data/');
//watcher
$hashContent = new Crc32ContentHash();
$resourceCache = new ResourceCachePhpFile('cache-key.php');
$watcher = new ResourceWatcher($resourceCache, $finder, $hashContent);
$watcher->initialize();
$changes = $watcher->findChanges();
if(!empty($changes->getUpdatedFiles())){
$updatedFilesPath = $changes->getUpdatedFiles();
$pathString = implode($updatedFilesPath);
$reader = Reader::createFromPath($pathString);
}
elseif(!empty($changes->getNewFiles())){
$newFilesPath = $changes->getNewFiles();
$pathString = implode($newFilesPath);
$reader = Reader::createFromPath($pathString);
}
else{
return;
}
$results = $reader->fetchAssoc();
So it looks like that as soon as you use the method findChanges()->hasChanges(), it tells the watcher that there is some changes but then it resets and there's no changes anymore in the watcher so it's pointless to use
$paths = $watcher->findChanges()->getUpdatedFiles();
since it will always return nothing because of the reset. I had to make a variable with the changes inside so that I could re-use the changes further down.
Details in code...

Is this a valid usage of the Factory pattern? multiple dependencies

I want to create a set of dependencies instead of injecting them everywhere. Would the factory pattern support this idea? Or is there another pattern for dealing with it?
For example:
class PassportCheckFactory {
protected $clientInstance;
protected $responseInstance;
public function buildDependancies() : bool
{
$this->clientInstance = new PassportCheckSoapClient;
$this->responseInstance = new PassportCheckResponse;
return true;
}
public function getResponseInstance()
{
return $this->responseInstance;
}
public function getClientInstance()
{
return $this->clientInstance;
}
}
This creates and holds the classes we would use, so we wouldn't need to inject them.
For example, we can do this
$request = new WhateverRequestClass;
$factory = (new PassportCheckFactory)->buildDependancies();
$service = new PassportCheckService($request, $factory);
$response = $service->execute();
instead of:
$request = new WhateverRequestClass;
$service = new PassportCheckService($request, new PassportCheckSoapClient, new PassportCheckResponse);
$response = $service->execute();
Your approach makes sense, if you want to support multiple CheckServices.
If PassportCheckService is the only one, the factory / service locator / specialised container from your example is just adding overhead.
$request = new WhateverRequestClass;
$service = new PassportCheckService($request, new PassportCheckSoapClient, new PassportCheckResponse);
$response = $service->execute();
is actually the best solution for a stand-alone service in terms of readability, maintainability and testabilty.
Multiple CheckServices
However, if you want to support multiple services, extracting the composition of the service into its own class brings benefits.
class CheckServiceFactory
{
public static function getService(Request $request, string $serviceType): CheckService
{
$type = ucfirst(strtolower($serviceType));
$serviceClass = $type . "CheckService";
$clientClass = $type . "CheckSoapClient";
$responseClass = $type . "CheckResponse";
return new $serviceClass($request, new $clientClass, new $responseClass);
}
}
Of course, the generation of the classnames depends on your naming scheme.
Calling a specific service would look like this:
$request = new WhateverRequestClass;
$service = CheckServiceFactory::getService($request, 'Passport');
$response = $service->execute();
Proposed Refactoring
Beside of the things above, I'd recommend to refactor the service class itself, so the request gets out of the constructor. That changes the usage
to:
$request = new WhateverRequestClass;
$service = CheckServiceFactory::getService('Passport');
$response = $service->handle($request);
or in case of a single service:
$request = new WhateverRequestClass;
$service = new PassportCheckService(new PassportCheckSoapClient, new PassportCheckResponse);
$response = $service->handle($request);
which actually looks much more straight forward.

How to use fixtures in WebTestCase PHPUnit

what I try to accomplish is:
Loading fresh fixtures in PHP code before a WebTestCase is executed. As far as i know this code should do its work:
// Get a kernel instance and boot it up!
static::$kernel = static::createKernel();
static::$kernel->boot();
// Get entity manager
$em = static::$kernel->getContainer()->get('doctrine_phpcr.odm.default_document_manager');
$loader = new Loader();
foreach (self::$fixturesRequired as $fixtureClass) {
$loader->addFixture(new $fixtureClass);
}
$purger = new ORMPurger($em);
$executor = new ORMExecutor($em, $purger);
$executor->execute($loader->getFixtures());
... but it fails with:
AnnounceControllerTest::testAnnounce
Argument 1 passed to Doctrine\Common\DataFixtures\Purger\ORMPurger::__construct() must be an instance of Doctrine\ORM\EntityManagerInterface, instance of Doctrine\ODM\PHPCR\DocumentManager given, called in /opt/development/cms/.../WebTestCase.php
So does anyone know what I'm missing?
Thanks a lot in advance :)
Solution to purge and load new fixtures for PHPCR:
// Get a kernel instance and boot it up!
static::$kernel = static::createKernel();
static::$kernel->boot();
// Get entity manager
$em = static::$kernel->getContainer()->get('doctrine_phpcr.odm.default_document_manager');
$loader = new Loader();
foreach (self::$fixturesRequired as $fixtureClass) {
$loader->addFixture(new $fixtureClass);
}
$purger = new PHPCRPurger($em);
$executor = new PHPCRExecutor($em, $purger);
$executor->execute($loader->getFixtures());
Thanks for the help!

DI Container - correct way of doing it?

I have a long list of dependency injections to display a page with an article, navigation, etc. And currently I put them in a file called index.php to glue them together.
index.php,
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
use MyCustomVerndorName\Slug\Mapper\SlugMapper;
.... (more)
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Nav model.
$NavModel = new NavModel();
$NavMapper = new NavMapper($PdoAdapter);
$NavService->setMapper($NavMapper)->setModel($NavModel);
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
... (more)
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
... (more)
$NavChildrenComponent = new NavChildrenComponent($PdoAdapter);
... (more)
// Inject components.
$NavMapper->addComponent($NavChildrenComponent);
$NavMapper->addComponent($NavLanguageComponent);
// Controll the slug.
$SlugController->setService($SlugService)->fetchRow([
"url" => $url
]);
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
in my router.php (I'm using AltoRouter),
use AltoRouter as Router;
$Router = new Router();.
$Router->map('GET', '/', '/article/container');
... (and other routes)
if($match)
{
$target = $match['target'];
$url = isset($match['params']['url']) ? $match['params']['url'] : DEFAULT_HOMEPAGE;
$language = isset($match['params']['language']) ? $match['params']['language'] : null;
include __DIR__ . $target . '.php';
}
I'm thinking to make the list of dependency injections in index.php into a container class so I can call this class whenever it is needed,
For instace in the router.php,
$Router->map('GET', '/', 'MyCustomVerndorName\Article\Container\ArticleContainer');
....
new $target($PdoAdapter, $url, $language);
And this container class,
namespace MyCustomVerndorName\Article\Container;
// Mapper.
use MyCustomVerndorName\Constant\Mapper\ConstantsMapper;
...
class ArticleContainer
{
/*
* Construct dependency.
*/
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
$ConstantService = new ConstantService();
$ConstantController = new ConstantController();
// Slug.
$SlugService = new SlugService();
$SlugController = new SlugController();
// Nav.
$NavService = new NavService();
$NavController = new NavController();
// Article.
$ArticleService = new ArticleService();
$ArticleController = new ArticleController();
// Prepare Article model.
$ArticleModel = new ArticleModel();
$ArticleMapper = new ArticleMapper($PdoAdapter);
// Prepare components.
$ArticleContentComponent = new ArticleContentComponent($PdoAdapter);
...
// Inject components.
$ArticleMapper->addComponent($ArticleContentComponent);
...
// Control the nav.
$NavController->setService($NavService)->fetchRows();
// Controll the article.
$ArticleService->setMapper($ArticleMapper)->setModel($ArticleModel);
$ArticleController->setService($ArticleService)->fetchRow([
"url" => $url
]);
// Prepare template.
$PageTemplate = new PageTemplate();
// Prepare view.
$ArticleView = new ArticleView($PageTemplate, $ArticleModel);
$ArticleView->setSlug($SlugModel);
$ArticleView->setNav($NavModel);
// Render the view.
echo $ArticleView->render('index.php');
}
}
Basically, I put all the dependency list into __construct,
public function __construct(\MyCustomVerndorName\Adapter\PdoAdapter $PdoAdapter, $url, $language)
{
...
}
So, is this the correct way of doing a DI Container without relying on the well known containers out there for PHP (such as Pimple, Symfony\DependencyInjection, etc)?
Traditionally, a DI container returns services upon demand. What you are calling ArticleContainer is really just a function then renders a view. It does a lot of DI injecting but it's not a container.
Let's assume you had a real container all properly initialized. Your code would look like:
$container = new Container();
// Some initialization
// Now use it
$viewArticle = $container->get('view_article');
echo $viewArticle->render('index.php');
Hopefully you can see the difference. Once the initialization is complete your application just pulls out the view it needs and renders it. No need to worry about pdo or url etc.
So how do we get our article view service into the container?
$container = new Container();
// Some initialization
$container->set('page_template',function($container)
{
return new PageTemplate();
}
$container->set('article_view',function($container)
{
$articleView = new ArticleView(
$container->get('page_template',
$container->get('article_model')
);
$articleView->setSlug($container->get('slug_model');
$articleView->setNav ($container->get('nav_model');
return $articleView;
};
// Now use it
$viewArticle = $container->get('article_view');
echo $viewArticle->render('index.php');
So we defined two service functions for our container. When we do $container->get('article_view');, the container calls the function with the container itself as an argument. The function creates the desired class by pulling dependencies out of the container and then returns the new object.
One assumes that you will probably have more page views in your application and that most of them will need a page_template. The same page_template service we defined can be used by your other views as well. So we start to get some reuse out of the container.
You basically just continue to add services to the container.
You can use Pimple for this but it's also instructive to make your own container. Really not much to it.

Categories