<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-14111654</id><updated>2026-05-06T15:32:26.500-07:00</updated><category term="PHP"/><category term="python"/><category term="docker"/><category term="macos"/><category term="ubuntu"/><category term="iOS"/><category term="iPad"/><category term="jquery"/><category term="Alternative PHP Cache"/><category term="Next.js"/><category term="fastapi"/><category term="linux"/><category term="APC"/><category term="Nusphere PhpExpress"/><category term="Zend Platform"/><category term="accelerator"/><category term="big sur"/><category term="container"/><category term="devops"/><category term="iPhone"/><category term="ionCube PHP Accelerator"/><category term="javascript"/><category term="keyboard"/><category term="multi-platform"/><category term="pyenv"/><category term="runtime"/><category term="vmware fusion"/><category term="--with-pylons"/><category term="10.10"/><category term="3.8"/><category term="4.2.2"/><category term="501"/><category term="APFS"/><category term="ATT"/><category term="Android"/><category term="Cheatsheets"/><category term="CyanogenMod 10.1"/><category term="Dockerfile"/><category term="Drupal"/><category term="Error"/><category term="ExFAT"/><category term="GIS"/><category term="JellyBean"/><category term="Mutiple views"/><category term="Openlayers"/><category term="Postgres"/><category term="RootViewController"/><category term="Samsung"/><category term="Skyrocket"/><category term="TWRP"/><category term="Turck MMCache"/><category term="UIImage"/><category term="UISplitViewController"/><category term="UITextField"/><category term="UITextView"/><category term="Unix"/><category term="VIX"/><category term="Windows"/><category term="XCache"/><category term="Zend Optimizer"/><category term="access-logs"/><category term="amd64"/><category term="assetPrefix"/><category term="async"/><category term="asyncio"/><category term="aws"/><category term="backlinks"/><category term="backup"/><category term="bash"/><category term="buttons"/><category term="cdn"/><category term="certificate verify failed"/><category term="clone file input"/><category term="color"/><category term="command line"/><category term="custom"/><category term="dialout"/><category term="drupal 6"/><category term="duply"/><category term="dynamic"/><category term="eAccelerator"/><category term="ecs"/><category term="ethernet"/><category term="external drive"/><category term="extract"/><category term="facebook"/><category term="false"/><category term="fargate"/><category term="file"/><category term="folders"/><category term="google-docs-api"/><category term="google-drive-sdk"/><category term="guest"/><category term="gui"/><category term="hide"/><category term="hiphop"/><category term="host"/><category term="httpd_can_sendmail"/><category term="httplib2"/><category term="implicit"/><category term="install"/><category term="java"/><category term="jdk"/><category term="line"/><category term="linkize"/><category term="logs"/><category term="macos sendfile"/><category term="mail"/><category term="match"/><category term="maverick"/><category term="meerkat"/><category term="middlware"/><category term="multi-stage"/><category term="multi-terminal"/><category term="multipass"/><category term="multiple python"/><category term="nest_asyncio"/><category term="nose"/><category term="nosetests"/><category term="opcode"/><category term="openapi"/><category term="output"/><category term="packer"/><category term="performance"/><category term="permissions"/><category term="pino"/><category term="postgis"/><category term="presentModalViewController"/><category term="print"/><category term="pylons"/><category term="pylons 1.0"/><category term="pylons 1.0.1"/><category term="qemu"/><category term="qemu-utils"/><category term="remove tabs"/><category term="rename tabs"/><category term="resignFirstResponder"/><category term="s3"/><category term="screen"/><category term="segmentation fault"/><category term="self-signed certificate"/><category term="selinux"/><category term="sendmail"/><category term="setup.cfg"/><category term="shared"/><category term="split"/><category term="sun"/><category term="swagger"/><category term="tar"/><category term="textfield"/><category term="textview"/><category term="tkinter"/><category term="toolbar"/><category term="trac"/><category term="untar"/><category term="unzip"/><category term="uvicorn"/><category term="viewport"/><category term="virtual network"/><category term="virtualenv"/><category term="virtualenvwrapper"/><category term="vm"/><category term="vmnet8"/><category term="vmware player"/><category term="vmware-iso"/><category term="web server"/><category term="with_pylons"/><category term="wont go"/><category term="xquartz"/><category term="yolk"/><title type='text'>Work Stuff - (Viraj Kanwade)</title><subtitle type='html'>something regarding programming and installations...&#xa;&lt;br&gt;&#xa;&lt;i&gt;Human knowledge belongs to the world!&lt;/i&gt;&#xa;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>58</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14111654.post-7099947612112000042</id><published>2025-09-08T13:16:00.000-07:00</published><updated>2025-09-08T13:17:45.320-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APFS"/><category scheme="http://www.blogger.com/atom/ns#" term="Error"/><category scheme="http://www.blogger.com/atom/ns#" term="ExFAT"/><category scheme="http://www.blogger.com/atom/ns#" term="external drive"/><category scheme="http://www.blogger.com/atom/ns#" term="macos"/><title type='text'>Why Your New External Drive is Breaking Your macOS Builds</title><content type='html'>&lt;div&gt;&lt;div&gt;Picture this: you&#39;re running dangerously low on disk space, so you invest in a brand new external drive. Time to migrate your development environment and get back to coding. You fire up those trusty setup scripts that have served you well for months, maybe years, and then...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Error.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What follows is the familiar developer dance of confusion and frustration. You scrutinize your scripts, double-check environment variables, recreate virtual environments, and question everything you thought you knew. In my case, I was staring at this cryptic message:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #ffa400;&quot;&gt;Unrecognized character \x05; marked by &amp;lt;-- HERE after &amp;lt;-- HERE near column 2 at ._Makefile.PL line 1.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The plot twist? When I recreated the exact same setup in &lt;span style=&quot;color: #ffa400;&quot;&gt;&lt;i&gt;/tmp&lt;/i&gt;&lt;/span&gt;, everything worked flawlessly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;The Mystery of the Phantom Files&lt;/h3&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A quick folder comparison revealed the smoking gun: nearly every file on my external drive had acquired a mysterious ._ companion. These weren&#39;t files I had created—they appeared seemingly out of nowhere.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;The Real Culprit: macOS&#39;s Metadata Workaround for ExFAT&lt;/h3&gt;&lt;div&gt;Here&#39;s what&#39;s actually happening behind the scenes. Most external drives ship with ExFAT formatting, which is great for cross-platform compatibility but has one significant limitation: it doesn&#39;t support Unix permissions or extended metadata that macOS relies on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Apple&#39;s solution? Store that metadata separately in hidden &lt;i&gt;&lt;span style=&quot;color: #ffa400;&quot;&gt;._FILENAME&lt;/span&gt;&lt;/i&gt; files. Clever, but problematic when your build tools start processing these metadata files as if they were actual source code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When my compilation process tried to build &lt;span style=&quot;color: #ffa400;&quot;&gt;&lt;i&gt;*.Makefile.PL&lt;/i&gt;&lt;/span&gt; files, it wasn&#39;t just finding the legitimate &lt;i&gt;&lt;span style=&quot;color: #ffa400;&quot;&gt;Makefile.PL&lt;/span&gt;&lt;/i&gt;—it was also attempting to compile &lt;span style=&quot;color: #ffa400;&quot;&gt;&lt;i&gt;._Makefile.PL&lt;/i&gt;&lt;/span&gt;, which contains binary metadata instead of valid Perl code. Hence the &quot;unrecognized character&quot; error.&lt;/div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;The Simple Fix&lt;/h3&gt;&lt;div&gt;The solution is straightforward: reformat your external drive to APFS (Apple File System). APFS natively supports the metadata and permissions that macOS expects, eliminating the need for those troublesome &lt;span style=&quot;color: #ffa400;&quot;&gt;._&lt;/span&gt; files.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Steps to resolve:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;1. Back up any important data from your external drive&lt;/div&gt;&lt;div&gt;2. Open Disk Utility&lt;/div&gt;&lt;div&gt;3. Select your external drive&lt;/div&gt;&lt;div&gt;4. Choose &quot;Erase&quot; and select APFS as the format&lt;/div&gt;&lt;div&gt;5. Restore your development environment&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Your build scripts will thank you, and you can get back to what matters: writing code instead of debugging phantom errors caused by phantom files.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7099947612112000042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7099947612112000042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7099947612112000042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7099947612112000042'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/09/why-your-new-external-drive-is-breaking.html' title='Why Your New External Drive is Breaking Your macOS Builds'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-3275002009360333101</id><published>2025-07-20T16:11:00.000-07:00</published><updated>2025-07-20T16:12:10.810-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="assetPrefix"/><category scheme="http://www.blogger.com/atom/ns#" term="cdn"/><category scheme="http://www.blogger.com/atom/ns#" term="container"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="Next.js"/><title type='text'>Reusing the same Next.js Docker image with runtime CDN assetPrefix</title><content type='html'>&lt;p&gt;Recently, while investigating a production issue, I needed to deploy the production Docker image locally for debugging purposes. However, I encountered a significant architectural constraint that highlighted a fundamental deployment challenge requiring both architectural and DevOps expertise to resolve.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;The Challenge: CDN Configuration&lt;/h3&gt;

&lt;p&gt;Next.js provides assetPrefix configuration to specify CDN or custom domains for static asset delivery, enabling faster content delivery through geographically distributed networks. However, this configuration presents a critical architectural constraint: &lt;b&gt;it&#39;s a build-time setting that gets permanently embedded into static pages and CSS assets.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This limitation creates substantial operational challenges when reusing a Docker image:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;b&gt;&lt;i&gt;Multiple Environments:&lt;/i&gt;&lt;/b&gt; Different environments like QA, stage, and production use different CDN domains.&lt;/li&gt;
    &lt;li&gt;&lt;b&gt;&lt;i&gt;Regional CDNs:&lt;/i&gt;&lt;/b&gt; Production environments could use different regional CDN domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The traditional approach would require building separate Docker images for each environment, violating the fundamental DevOps principle of &quot;build once, deploy anywhere.&quot;&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Architectural Solution: Runtime Asset Prefix Injection&lt;/h3&gt;

&lt;p&gt;Through careful analysis of Next.js&#39;s asset handling mechanisms and strategic use of text replacement techniques, I developed a solution that maintains build-time optimization while enabling runtime CDN configuration.&lt;/p&gt;

&lt;h4 style=&quot;text-align: left;&quot;&gt;Configuration Architecture&lt;/h4&gt;

&lt;p&gt;The solution begins with environment-aware configuration that handles both &lt;b&gt;&lt;i&gt;basePath&lt;/i&gt;&lt;/b&gt; and &lt;b&gt;&lt;i&gt;assetPrefix&lt;/i&gt;&lt;/b&gt; dynamically:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mavwolverine/bc6fcfdd0f1180ea73bf5a57f05b9000.js?file=next.config.mjs&quot;&gt;&lt;/script&gt;

&lt;h4 style=&quot;text-align: left;&quot;&gt;Docker Build Strategy&lt;/h4&gt;

&lt;p&gt;During the Docker image creation process, we set placeholder values that will be replaced at runtime, along with a custom entrypoint script:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mavwolverine/bc6fcfdd0f1180ea73bf5a57f05b9000.js?file=Dockerfile&quot;&gt;&lt;/script&gt;

&lt;h4 style=&quot;text-align: left;&quot;&gt;Runtime Replacement Logic&lt;/h4&gt;

&lt;p&gt;The entrypoint script performs intelligent text replacement, substituting placeholder values with environment-specific configurations at container startup:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/mavwolverine/bc6fcfdd0f1180ea73bf5a57f05b9000.js?file=my-docker-entrypoint.sh&quot;&gt;&lt;/script&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Addressing Image Security Constraints&lt;/h3&gt;

&lt;p&gt;During implementation, I encountered an additional architectural challenge: Next.js image optimization returns cryptic 404 errors when serving images from CDN domains. Investigation into the Next.js source code revealed this is a security feature that only allows pre-approved domains for image serving.&lt;/p&gt;

&lt;p&gt;The error message &quot;url parameter is not allowed&quot; provides insufficient context for troubleshooting, but the root cause is Next.js&#39;s domain whitelist mechanism. This requires configuring &lt;b&gt;&lt;i&gt;images.remotePatterns&lt;/i&gt;&lt;/b&gt; to explicitly allow CDN domains.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Advanced Runtime Configuration&lt;/h3&gt;

&lt;p&gt;The most sophisticated aspect of this solution involves dynamically updating the remotePatterns configuration at runtime. Since we&#39;re performing text replacements on configuration files, I leveraged Node.js&#39;s command-line execution capabilities to add intelligent remotePatterns generation for CDN domain whitelisting.&lt;/p&gt;

&lt;p&gt;This approach ensures that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Security policies&lt;/i&gt;&lt;/b&gt; remain enforced through domain whitelisting&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Runtime flexibility&lt;/i&gt;&lt;/b&gt; is maintained for multi-environment deployments&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Performance optimization&lt;/i&gt;&lt;/b&gt; continues through proper CDN utilization&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Operational efficiency&lt;/i&gt;&lt;/b&gt; is achieved through single-image deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Key Architectural Benefits&lt;/h3&gt;

&lt;p&gt;This solution delivers several critical advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Single Image Deployment:&lt;/i&gt;&lt;/b&gt; One Docker image serves all environments, reducing build complexity and storage requirements&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Runtime Flexibility:&lt;/i&gt;&lt;/b&gt; CDN configurations adapt to deployment context without rebuild cycles&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Performance Preservation:&lt;/i&gt;&lt;/b&gt; Static page optimization remains intact while enabling dynamic asset serving&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Security Compliance:&lt;/i&gt;&lt;/b&gt; Domain whitelisting ensures controlled image processing&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Operational Simplicity:&lt;/i&gt;&lt;/b&gt; Environment-specific configurations are managed through standard environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Implementation Considerations&lt;/h3&gt;

&lt;p&gt;When implementing this approach, consider these architectural factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Text replacement scope:&lt;/i&gt;&lt;/b&gt; Ensure replacements target only intended configuration values&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Environment variable validation:&lt;/i&gt;&lt;/b&gt; Implement proper fallbacks for missing or invalid CDN configurations&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Security boundaries:&lt;/i&gt;&lt;/b&gt; Maintain strict domain whitelisting for image processing&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Performance monitoring:&lt;/i&gt;&lt;/b&gt; Verify that runtime replacements don&#39;t impact application startup time&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;With some architectural creativity, we can resolve platform limitations while maintaining operational best practices. By combining Next.js&#39;s build-time optimizations with runtime configuration flexibility, we achieve the ideal balance of performance and deployment efficiency.&lt;/p&gt;

&lt;p&gt;The approach enables teams to leverage CDN benefits across multiple environments while adhering to containerization principles, ultimately delivering both technical excellence and operational simplicity. For organizations deploying Next.js applications across diverse environments, this pattern provides a production-ready solution that scales with architectural complexity while maintaining deployment consistency.&lt;/p&gt;

</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/3275002009360333101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/3275002009360333101' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3275002009360333101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3275002009360333101'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/07/reusing-same-nextjs-docker-image-with.html' title='Reusing the same Next.js Docker image with runtime CDN assetPrefix'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-905699759552131333</id><published>2025-07-20T11:53:00.000-07:00</published><updated>2025-07-20T16:12:48.473-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="container"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="ecs"/><category scheme="http://www.blogger.com/atom/ns#" term="fargate"/><category scheme="http://www.blogger.com/atom/ns#" term="Next.js"/><title type='text'>Resolving Next.js Standalone Build Docker Reachability Failure on AWS ECS Fargate</title><content type='html'>&lt;p&gt;While deploying a Next.js standalone build in a Docker container on AWS ECS Fargate, I encountered a subtle but critical issue that highlights the importance of understanding platform-specific runtime behaviors.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;The Problem: Silent Health Check Failures&lt;/h3&gt;

&lt;p&gt;During the deployment of our Next.js application to AWS ECS Fargate, the service consistently failed health checks despite the application appearing to function correctly. The container would start successfully, but the Target Group couldn&#39;t establish connectivity, resulting in deployment failures.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Initial Investigation&lt;/h3&gt;

&lt;p&gt;Examining the container logs revealed the root cause:&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre; width:470px; overflow-inline: auto;&quot;&gt;- Local:    http://ip-10-0-5-61.us-west-2.compute.internal:3000
- Network:  http://10.0.5.61:3000
&lt;/div&gt;


&lt;p&gt;The Next.js server was binding to the container&#39;s internal hostname rather than accepting connections from external networks. This prevented the ALB health checks from reaching the application endpoint.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Root Cause Analysis&lt;/h3&gt;

&lt;p&gt;Tracing through the Next.js standalone build revealed the hostname configuration logic in server.js:&lt;/p&gt;

&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre; width:470px; overflow-inline: auto;&quot;&gt;const currentPort = parseInt(process.env.PORT, 10) || 3000
const hostname = process.env.HOSTNAME || &#39;0.0.0.0&#39;
&lt;/div&gt;


&lt;p&gt;The application defaults to 0.0.0.0 (accepting all connections) when no HOSTNAME environment variable is present. My initial approach was to explicitly set HOSTNAME=0.0.0.0 in the ECS task definition.&lt;/p&gt;

&lt;p&gt;However, this approach failed due to a critical AWS Fargate behavior: &lt;b&gt;&lt;i&gt;Fargate automatically sets the HOSTNAME environment variable at runtime&lt;/i&gt;&lt;/b&gt;, overriding any pre-configured values.&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Evaluating Solution Approaches&lt;/h3&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Approach 1: Runtime Environment Override&lt;/h4&gt;
  &lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre; width:470px; overflow-inline: auto;&quot;&gt;CMD &quot;HOSTNAME=0.0.0.0 node server.js&quot;
&lt;/div&gt;


&lt;p&gt;While functional, this approach embeds environment variable assignments within the CMD instruction, reducing container portability and maintainability.&lt;/p&gt;

&lt;h4 style=&quot;text-align: left;&quot;&gt;Approach 2: Build-Time Source Modification&lt;/h4&gt;
&lt;p&gt;Using &lt;b&gt;&lt;i&gt;sed&lt;/i&gt;&lt;/b&gt; during the Docker build process to directly modify the hostname assignment:&lt;/p&gt;

&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre; width:470px; overflow-inline: auto;&quot;&gt;RUN sed -i &quot;s/const hostname = process.env.HOSTNAME || &#39;0.0.0.0&#39;/const hostname = &#39;0.0.0.0&#39;/g&quot; server.js
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Approach 3: Systematic Source Patching (Recommended as it provides consistent behavior locally and in the cloud)&lt;/h4&gt;

&lt;p&gt;The most architecturally sound solution leverages patch-package to modify the Next.js build process itself. The hostname assignment originates from &lt;i&gt;node_modules/next/dist/build/utils.js&lt;/i&gt; in the writeFile function that generates server.js.&lt;/p&gt;

&lt;p&gt;By creating a systematic patch that modifies the server generation logic, we achieve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Consistency across environments&lt;/i&gt;&lt;/b&gt; (local development and production)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Maintainability&lt;/i&gt;&lt;/b&gt; through version-controlled patches&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Architectural integrity&lt;/i&gt;&lt;/b&gt; by addressing the root cause rather than symptoms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Implementation Details&lt;/h3&gt;

&lt;p&gt;The patch modifies the server template generation in Next.js build to use more relevant environment variable names. This ensures consistent behavior across all deployment targets while maintaining clean separation of concerns.&lt;/p&gt;

&lt;p&gt;&lt;script src=&quot;https://gist.github.com/mavwolverine/3a41a1f5a81931ef8a783c032e137c16.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Key Architectural Insights&lt;/h3&gt;

&lt;p&gt;This experience reinforces several important principles for cloud-native application deployment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Platform Behavior Awareness:&lt;/i&gt;&lt;/b&gt; Cloud platforms often inject runtime configurations that can override application-level settings&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Health Check Design:&lt;/i&gt;&lt;/b&gt; Container applications must be designed with load balancer connectivity patterns in mind&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Source-Level Solutions:&lt;/i&gt;&lt;/b&gt; Sometimes the most maintainable solution requires modifying the build process rather than working around runtime constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;text-align: left;&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;While AWS Fargate&#39;s automatic hostname assignment serves legitimate infrastructure purposes, it can create unexpected challenges for containerized applications. By understanding the platform&#39;s behavior and implementing systematic source modifications, we can create robust deployment solutions that maintain architectural integrity while meeting operational requirements.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/905699759552131333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/905699759552131333' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/905699759552131333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/905699759552131333'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/07/resolving-nextjs-standalone-build.html' title='Resolving Next.js Standalone Build Docker Reachability Failure on AWS ECS Fargate'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-45238927541757461</id><published>2025-07-19T21:40:00.000-07:00</published><updated>2025-07-19T22:13:27.640-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="access-logs"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="Dockerfile"/><category scheme="http://www.blogger.com/atom/ns#" term="logs"/><category scheme="http://www.blogger.com/atom/ns#" term="Next.js"/><category scheme="http://www.blogger.com/atom/ns#" term="pino"/><title type='text'>Access logs in Next.js production build</title><content type='html'>&lt;p&gt;I frequently encounter architectural decisions that seem counterintuitive from an operational perspective. Recently,
    while containerizing a Next.js application, I discovered one such puzzling design choice that required a creative
    engineering solution.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;The Problem: Silent Production Builds&lt;/h4&gt;
&lt;p&gt;During the Docker image creation process for our Next.js application, I encountered an unexpected operational blind
  spot: &lt;i&gt;Next.js production builds generate zero access logs.&lt;/i&gt; This absence of fundamental observability data
    immediately raised concerns about our ability to monitor application behavior in production environments.&lt;/p&gt;
&lt;p&gt;The conventional wisdom suggests deploying an nginx reverse proxy to capture access logs. However, as an architect
    focused on operational efficiency, introducing an additional process layer solely for logging felt architecturally
    unsound, particularly within containerized environments where process minimalism is a core principle.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Exploring Conventional Solutions&lt;/h4&gt;
&lt;p&gt;My initial investigation led me to application-level logging libraries such as &lt;b&gt;&lt;i&gt;winston&lt;/i&gt;&lt;/b&gt; and
    &lt;b&gt;&lt;i&gt;pino&lt;/i&gt;&lt;/b&gt;. While these tools excel at application logging, they operate within the application boundary and
    don&#39;t provide the standardized access log format that operations teams expect from web applications.
&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Root Cause Analysis&lt;/h4&gt;
&lt;p&gt;After extensive research into similar reported issues, I discovered the underlying cause: &lt;i&gt;Vercel has intentionally
  omitted access logging from Next.js production builds.&lt;/i&gt; This architectural decision, while perhaps suitable for
    Vercel&#39;s managed platform, creates operational challenges for self-hosted deployments.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Deep Dive&lt;/h4&gt;
&lt;p&gt;Taking a source-code-first approach, I downloaded the Next.js repository and traced the request handling flow to its
    core: the &lt;b&gt;&lt;i&gt;async function requestListener(req, res)&lt;/i&gt;&lt;/b&gt; function. By strategically placing console.log
    statements within the node_modules Next.js installation, I successfully exposed the access log data we needed.&lt;/p&gt;
&lt;p&gt;However, this manual modification approach presented obvious maintainability challenges for automated deployment
    pipelines.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Production-Ready Implementation&lt;/h4&gt;
&lt;p&gt;While researching sustainable patching methodologies, I discovered an excellent resource by TomUps
    (&lt;a href=&quot;https://www.tomups.com/posts/log-nextjs-request-response-as-json/&quot;&gt;https://www.tomups.com/posts/log-nextjs-request-response-as-json/&lt;/a&gt;)
    that introduced patch-package, a tool designed precisely for this type of systematic source modification.&lt;/p&gt;
&lt;p&gt;Their approach provided the foundational technique, though it captured extensive request/response metadata including
    headers and body content. For our operational requirements, I needed a more focused solution that provided essential
    access log fields: timestamp, URL, and HTTP status code.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Architectural Solution&lt;/h4&gt;
&lt;p&gt;The final implementation leverages &lt;b&gt;&lt;i&gt;patch-package&lt;/i&gt;&lt;/b&gt; combined with &lt;b&gt;&lt;i&gt;pino-http-print&lt;/i&gt;&lt;/b&gt; to deliver
    clean, standardized access logs that integrate seamlessly with our existing observability stack. This approach:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt; &lt;b&gt;&lt;i&gt;container efficiency&lt;/i&gt;&lt;/b&gt; by avoiding additional processes&lt;/li&gt;
    &lt;li&gt; &lt;b&gt;&lt;i&gt;Provides operational visibility&lt;/i&gt;&lt;/b&gt; through standard access log formats&lt;/li&gt;
    &lt;li&gt; &lt;b&gt;&lt;i&gt;Ensures deployment consistency&lt;/i&gt;&lt;/b&gt; via automated patching during image builds&lt;/li&gt;
    &lt;li&gt; &lt;b&gt;&lt;i&gt;Preserves maintainability&lt;/i&gt;&lt;/b&gt; through version-controlled patch files&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Key Takeaway&lt;/h4&gt;
&lt;p&gt;This experience reinforces a fundamental architectural principle: when platform decisions conflict with operational
    requirements, creative engineering solutions can bridge the gap while maintaining system integrity. The key is
    balancing pragmatic problem-solving with long-term maintainability, exactly what patch-package enables in this
    scenario.&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;Steps&lt;/h4&gt;
&lt;p&gt;
  	You can follow the steps in TomUps post and use the following patch.
    &lt;script src=&quot;https://gist.github.com/mavwolverine/ee529eca7f1e41f1af150249f22e5f16.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/45238927541757461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/45238927541757461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/45238927541757461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/45238927541757461'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/07/access-logs-in-nextjs-production-build.html' title='Access logs in Next.js production build'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-8467947502465708192</id><published>2025-05-22T09:13:00.000-07:00</published><updated>2025-05-22T09:13:22.341-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="amd64"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="multi-platform"/><category scheme="http://www.blogger.com/atom/ns#" term="qemu"/><category scheme="http://www.blogger.com/atom/ns#" term="segmentation fault"/><title type='text'>Segmentation fault when running pip inside docker buildx on host=arm platform=amd64</title><content type='html'>&lt;div&gt;Following Docker&#39;s transition to a paid licensing model for Docker Desktop, I migrated our development environment to Rancher Desktop, which offers integrated support for both Docker and Kubernetes functionalities. During a recent initiative to convert legacy Docker images to multi-platform images, I encountered an unusual issue.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;During the buildx build, the `pip install` command was failing with a segmentation fault error, despite the same installation steps executing flawlessly in an interactive container environment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;Initial Troubleshooting Efforts&lt;/h4&gt;&lt;div&gt;Further investigation revealed:&lt;/div&gt;&lt;div&gt;1. The ARM64 architecture builds completed successfully, while AMD64 builds consistently failed&lt;/div&gt;&lt;div&gt;2. The failures were isolated to two specific Python packages: pycrypto and uWSGI&lt;/div&gt;&lt;div&gt;3. Standard remediation approaches suggested on various posts were ineffective, including:&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Modifying Python versions&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Updating pip&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Testing alternative package versions&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Installing supplementary system libraries&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Switching between base images (python:3.8-slim (Debian bookworm), Debian bullseye, Ubuntu)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;- Using root installation instead of virtual environments&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;Root Cause Analysis&lt;/h4&gt;&lt;div&gt;After extensive troubleshooting, I identified that the failures stemmed from cross-architecture compilation requirements. Both uWSGI and pycrypto lack pre-built wheels, necessitating compilation during installation. This compilation process was failing specifically when building AMD64 binaries on ARM64 host architecture.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Shifting my focus to the underlying virtualization platform, I searched for issues related to QEMU emulation and segmentation faults on AMD64 platforms. A comment on a relevant post suggested trying the build process on Docker Desktop.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;Resolution&lt;/h4&gt;&lt;div&gt;After reinstalling Docker Desktop, I was able to successfully build the image.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To verify the findings, I retested all previous versions of the Dockerfile, and they worked as expected.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;Conclusion&lt;/h4&gt;&lt;div&gt;The root cause of this issue lies in the QEMU virtualization framework&#39;s emulation of AMD64 architectures on ARM-based systems.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While ARM support has matured considerably across the board, such cases represent areas requiring further development attention from the community.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;NOTE&lt;/h4&gt;&lt;div&gt;To facilitate easy reuse and streamline the build process, I recommend creating a builder&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;docker&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;buildx&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;create&lt;/span&gt; \&lt;/div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;    --name&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;multi-platform-docker&lt;/span&gt; \&lt;/div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;    --driver&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;docker-container&lt;/span&gt; \&lt;/div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;    --platform&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;linux/amd64,linux/arm64&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;To utilize this builder, run the following command:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;docker&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;buildx&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;--builder&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;multi-platform-docker&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;build&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/8467947502465708192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/8467947502465708192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8467947502465708192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8467947502465708192'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/05/segmentation-fault-when-running-pip.html' title='Segmentation fault when running pip inside docker buildx on host=arm platform=amd64'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-8471888124842968638</id><published>2025-05-19T11:20:00.000-07:00</published><updated>2025-05-20T09:07:39.152-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="multi-platform"/><category scheme="http://www.blogger.com/atom/ns#" term="multi-stage"/><title type='text'>Multi-platform multi-stage build docker images with platform specific files</title><content type='html'>&lt;p&gt;&amp;nbsp;While working on multi platform docker images for a FastAPI application with MySQL client libraries, ran into a scenario where the MySQL library files are stored in platform specific paths.&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 12px; padding: 10px; white-space: pre;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;/usr/lib/x86_64-linux-gnu&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;/usr/lib/aarch64-linux-gnu&lt;/div&gt;&lt;/div&gt;
  &lt;p&gt;As part of multi-stage build, I wanted to do something like&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;p&gt;FROM python:${PYTHON_VERSION}-slim&lt;/p&gt;&lt;p&gt;# if x64&lt;/p&gt;&lt;p&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu&lt;/p&gt;&lt;p&gt;# if arm&lt;/p&gt;&lt;p&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;But there is no conditional platform support at the COPY command level. It is only at the FROM level.&lt;/p&gt;&lt;p&gt;The simple solution would be to have duplicate final image setup.&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;FROM --platform=amd64 python:${PYTHON_VERSION}-slim&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu&lt;br /&gt;...&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;FROM --platform=arm64 python:${PYTHON_VERSION}-slim&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu&lt;br /&gt;...&lt;/div&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;But this would mean duplicating rest of the steps too.&lt;/p&gt;&lt;p&gt;The solution is to create multiple platform specific intermediate images and use them to create the final image.&lt;/p&gt;
&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; padding: 10px; white-space: pre;&quot;&gt;&lt;div&gt;FROM --platform=amd64 python:${PYTHON_VERSION}-slim as final-intermediate-amd64&lt;/div&gt;&lt;div&gt;&lt;br /&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/libmaria* /usr/lib/x86_64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/*xslt* /usr/lib/x86_64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/x86_64-linux-gnu/*xml* /usr/lib/x86_64-linux-gnu&lt;br /&gt;&lt;br /&gt;FROM --platform=arm64 python:${PYTHON_VERSION}-slim as final-intermediate-arm64&lt;/div&gt;&lt;div&gt;&lt;br /&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/libmaria* /usr/lib/aarch64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/*xslt* /usr/lib/aarch64-linux-gnu&lt;br /&gt;COPY --from=builder /usr/lib/aarch64-linux-gnu/*xml* /usr/lib/aarch64-linux-gnu&lt;br /&gt;&lt;br /&gt;FROM final-intermediate-${TARGETARCH}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;COPY . /code/&lt;br /&gt;COPY requirements.txt /code/requirements.txt&lt;br /&gt;COPY --from=builder /code/.venv /code/.venv&lt;br /&gt;COPY --from=builder /usr/bin/mysql_config /usr/bin&lt;/div&gt;&lt;div&gt;&lt;br /&gt;WORKDIR /code&lt;/div&gt;&lt;div&gt;&lt;br /&gt;EXPOSE 8000&lt;/div&gt;&lt;div&gt;&lt;br /&gt;CMD [&quot;/code/.venv/bin/uvicorn&quot;, &quot;--app-dir&quot;, &quot;/code/myapp&quot;, &quot;server:app&quot;, &quot;--proxy-headers&quot;]&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/8471888124842968638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/8471888124842968638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8471888124842968638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8471888124842968638'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2025/05/multi-platform-multi-stage-build-docker.html' title='Multi-platform multi-stage build docker images with platform specific files'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-7356345005712372037</id><published>2024-05-13T11:01:00.000-07:00</published><updated>2024-05-13T11:01:56.018-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fastapi"/><category scheme="http://www.blogger.com/atom/ns#" term="middlware"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><title type='text'>FastAPI middleware performance</title><content type='html'>&lt;p&gt;&amp;nbsp;As per the &lt;a href=&quot;https://fastapi.tiangolo.com/tutorial/middleware/&quot; target=&quot;_blank&quot;&gt;FastAPI docs&lt;/a&gt;, the way to create and add custom middlewares is&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=&quot;color: #dcdcaa;&quot;&gt;@app.middleware&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;http&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;async&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;add_my_middlware&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;request&lt;/span&gt;: Request, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;call_next&lt;/span&gt;):&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;call_next&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;request&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Seems simple enough. Before the await, you can do something with the request. After the await, you can do something with the response.&lt;/p&gt;&lt;p&gt;But if you run benchmark, you will find something very surprising.&lt;/p&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;Lets check a vanilla FastAPI&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;fastapi&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #dcdcaa;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;/&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;read_root&lt;/span&gt;():&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; {&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;Hello&quot;&lt;/span&gt;: &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;World&quot;&lt;/span&gt;}&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/wg/wrk&quot; target=&quot;_blank&quot;&gt;wrk&lt;/a&gt; benchmark&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  ❯ wrk -t12 -c400 -d30s http://localhost:9001&lt;/div&gt;&lt;div style=&quot;line-height: 18px;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;  Running 30s test @ http://localhost:9001&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;12&lt;/span&gt; threads and &lt;span style=&quot;color: #b5cea8;&quot;&gt;400&lt;/span&gt; connections&lt;/div&gt;&lt;div&gt;    Thread Stats   Avg      Stdev     Max   +/- Stdev&lt;/div&gt;&lt;div&gt;      Latency    36.46ms    6.81ms 215.22ms   90.89%&lt;/div&gt;&lt;div&gt;      Req/Sec     0.91k    60.89     1.24k    72.67%&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;326354&lt;/span&gt; requests in 30.08s, 44.20MB read&lt;/div&gt;&lt;div&gt;    Socket errors: connect 0, read 1298, write 0, &lt;span style=&quot;color: #569cd6;&quot;&gt;timeout&lt;/span&gt; &lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  Requests/sec:  10849.19&lt;/div&gt;&lt;div&gt;  Transfer/sec:      1.47MB&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;p&gt;Now, with middleware as suggested by FastAPI docs&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;fastapi&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;, &lt;span style=&quot;color: #4ec9b0;&quot;&gt;Request&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #dcdcaa;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;middleware&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;http&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;async&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;add_my_middlware&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;request&lt;/span&gt;: &lt;span style=&quot;color: #4ec9b0;&quot;&gt;Request&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;call_next&lt;/span&gt;):&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;call_next&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;request&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #dcdcaa;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;/&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;read_root&lt;/span&gt;():&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; {&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;Hello&quot;&lt;/span&gt;: &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;World&quot;&lt;/span&gt;}&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;wrk benchmark&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  ❯ wrk -t12 -c400 -d30s http://localhost:9002&lt;/div&gt;&lt;div&gt;  Running 30s test @ http://localhost:9002&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;12&lt;/span&gt; threads and &lt;span style=&quot;color: #b5cea8;&quot;&gt;400&lt;/span&gt; connections&lt;/div&gt;&lt;div&gt;    Thread Stats   Avg      Stdev     Max   +/- Stdev&lt;/div&gt;&lt;div&gt;      Latency    78.72ms   16.38ms 379.75ms   95.50%&lt;/div&gt;&lt;div&gt;      Req/Sec   420.40     45.60   710.00     78.94%&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;151008&lt;/span&gt; requests in 30.09s, 20.45MB read&lt;/div&gt;&lt;div&gt;    Socket errors: connect 0, read 1395, write 16, &lt;span style=&quot;color: #569cd6;&quot;&gt;timeout&lt;/span&gt; &lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  Requests/sec:   5018.51&lt;/div&gt;&lt;div&gt;  Transfer/sec:    695.94KB&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Notice anything?&lt;/p&gt;&lt;p&gt;The &quot;Requests/sec&quot; went down from 10849 to 5018. That is a close to 54% drop.&lt;/p&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;p&gt;Lets look at &lt;a href=&quot;http://@app.middlware&quot; target=&quot;_blank&quot;&gt;@app.middlware&lt;/a&gt;&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;starlette&lt;/span&gt;.&lt;span style=&quot;color: #4ec9b0;&quot;&gt;middleware&lt;/span&gt;.&lt;span style=&quot;color: #4ec9b0;&quot;&gt;base&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;BaseHTTPMiddleware&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;self&lt;/span&gt;.add_middleware(&lt;span style=&quot;color: #4ec9b0;&quot;&gt;BaseHTTPMiddleware&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt;func)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;The starlette BaseHTTPMiddleware is known for its issues. But one undocumented issue seems to be performance.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;https://www.starlette.io/middleware/#limitations&lt;/li&gt;&lt;li&gt;https://github.com/encode/starlette/issues/1678&lt;/li&gt;&lt;li&gt;https://github.com/encode/starlette/discussions/1729&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;p&gt;So what is the alternative?&lt;/p&gt;&lt;p&gt;Write Pure ASGI Middleware!&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;fastapi&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;starlette&lt;/span&gt;.&lt;span style=&quot;color: #4ec9b0;&quot;&gt;types&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; (&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #9cdcfe;&quot;&gt;ASGIApp&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Message&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Receive&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Scope&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Send&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  )&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;FastAPI&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;ASGIMiddleware&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;__init__&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;self&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;: &lt;span style=&quot;color: #9cdcfe;&quot;&gt;ASGIApp&lt;/span&gt;) -&amp;gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;None&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #569cd6;&quot;&gt;async&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;__call__&lt;/span&gt;(&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;self&lt;/span&gt;, &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;scope&lt;/span&gt;: &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Scope&lt;/span&gt;, &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;receive&lt;/span&gt;: &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Receive&lt;/span&gt;, &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;send&lt;/span&gt;: &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Send&lt;/span&gt;&lt;/div&gt;&lt;div&gt;      ) -&amp;gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;None&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #c586c0;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;scope&lt;/span&gt;[&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;type&quot;&lt;/span&gt;] &lt;span style=&quot;color: #d4d4d4;&quot;&gt;!=&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;http&quot;&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #c586c0;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;scope&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;receive&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;send&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #9cdcfe;&quot;&gt;messages&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; []&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #6a9955;&quot;&gt;# Create a new send channel which can be called&lt;/span&gt;&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #6a9955;&quot;&gt;# multiple times with a single event&lt;/span&gt;&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #569cd6;&quot;&gt;async&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;send_wrapper&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;message&lt;/span&gt;: &lt;span style=&quot;color: #9cdcfe;&quot;&gt;Message&lt;/span&gt;):&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #6a9955;&quot;&gt;# Read a single message&lt;/span&gt;&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #9cdcfe;&quot;&gt;messages&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;append&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;message&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #9cdcfe;&quot;&gt;more_body&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;message&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;more_body&quot;&lt;/span&gt;, &lt;span style=&quot;color: #569cd6;&quot;&gt;False&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #6a9955;&quot;&gt;# If the body is not complete yet, return to wait&lt;/span&gt;&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #c586c0;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;more_body&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;                  &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #6a9955;&quot;&gt;# The body is complete, you can now access it&lt;/span&gt;&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #9cdcfe;&quot;&gt;body&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;&quot;&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;join&lt;/span&gt;([&lt;span style=&quot;color: #9cdcfe;&quot;&gt;message&lt;/span&gt;.get(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;body&quot;&lt;/span&gt;, &lt;span style=&quot;color: #569cd6;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;                               &lt;span style=&quot;color: #c586c0;&quot;&gt;for&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;message&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;in&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;messages&lt;/span&gt;])&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #6a9955;&quot;&gt;# Replay all the messages&lt;/span&gt;&lt;/div&gt;&lt;div&gt;              &lt;span style=&quot;color: #c586c0;&quot;&gt;while&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;messages&lt;/span&gt;:&lt;/div&gt;&lt;div&gt;                  &lt;span style=&quot;color: #c586c0;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;send&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;messages&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;pop&lt;/span&gt;(&lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;))&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #6a9955;&quot;&gt;# Pass the new send channel to the downstream application&lt;/span&gt;&lt;/div&gt;&lt;div&gt;          &lt;span style=&quot;color: #c586c0;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;scope&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;receive&lt;/span&gt;, &lt;span style=&quot;color: #dcdcaa;&quot;&gt;send_wrapper&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;add_middleware&lt;/span&gt;(&lt;span style=&quot;color: #4ec9b0;&quot;&gt;ASGIMiddleware&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #dcdcaa;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;/&quot;&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;read_root&lt;/span&gt;():&lt;/div&gt;&lt;div&gt;      &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; {&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;Hello&quot;&lt;/span&gt;: &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;World&quot;&lt;/span&gt;}&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;That looks like a lot of code.&lt;/p&gt;&lt;p&gt;Also, the other problem will be understanding the flow.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Since the ASGI middleware works at a different level, you no longer have access to request and response objects. Instead, the middleware deals with messages. Even the response body could be received across multiple messages. Read up at&amp;nbsp;&lt;a href=&quot;https://asgi.readthedocs.io/en/latest/specs/www.html#http-websocket-asgi-message-format&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Now lets run the benchmark again.&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  ❯ wrk -t12 -c400 -d30s http://localhost:9003&lt;/div&gt;&lt;div&gt;  Running 30s test @ http://localhost:9003&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;12&lt;/span&gt; threads and &lt;span style=&quot;color: #b5cea8;&quot;&gt;400&lt;/span&gt; connections&lt;/div&gt;&lt;div&gt;    Thread Stats   Avg      Stdev     Max   +/- Stdev&lt;/div&gt;&lt;div&gt;      Latency    38.73ms    7.68ms 219.67ms   90.27%&lt;/div&gt;&lt;div&gt;      Req/Sec     0.86k    74.66     1.09k    74.94%&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #b5cea8;&quot;&gt;307336&lt;/span&gt; requests in 30.07s, 41.62MB read&lt;/div&gt;&lt;div&gt;    Socket errors: connect 0, read 1237, write 5, &lt;span style=&quot;color: #569cd6;&quot;&gt;timeout&lt;/span&gt; &lt;span style=&quot;color: #b5cea8;&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  Requests/sec:  10220.39&lt;/div&gt;&lt;div&gt;  Transfer/sec:      1.38MB&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;Requests/sec: Vanilla FastAPI - 10849 vs with ASGI middleware 10220.&lt;/p&gt;&lt;p&gt;That&#39;s only about 6% drop in performance.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7356345005712372037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7356345005712372037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7356345005712372037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7356345005712372037'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2024/05/fastapi-middleware-performance.html' title='FastAPI middleware performance'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-2058028562136585249</id><published>2024-05-11T07:20:00.000-07:00</published><updated>2024-05-11T07:22:11.120-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="async"/><category scheme="http://www.blogger.com/atom/ns#" term="asyncio"/><category scheme="http://www.blogger.com/atom/ns#" term="fastapi"/><category scheme="http://www.blogger.com/atom/ns#" term="nest_asyncio"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="uvicorn"/><title type='text'>Python - calling async function from a sync code flow</title><content type='html'>&lt;p&gt;&amp;nbsp;Recently I ran into a scenario where I needed to call a init function for a third party library in my FastAPI application. The problem was, the function was async.&lt;/p&gt;&lt;p&gt;One way of calling an async function from a sync flow is using asyncio event loop.&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt; &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get_event_loop&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;run_until_complete&lt;/span&gt;(init())&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;But this gave event loop is already running error.&lt;/p&gt;&lt;p&gt;The problem is, FastAPI application is run with uvicorn which starts a loop.&lt;/p&gt;&lt;p&gt;So I tried creating a new loop.&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; asyncio.new_event_loop()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  asyncio.set_event_loop(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;.run_until_complete(init())&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;p&gt;But this still didn&#39;t work as asyncio only supports one loop at a time.&lt;/p&gt;&lt;p&gt;The most suggested approach is to use&amp;nbsp;&lt;a href=&quot;https://pypi.org/project/nest-asyncio/&quot; target=&quot;_blank&quot;&gt;nest-asyncio&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;nest_asyncio&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; asyncio.new_event_loop()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #4ec9b0;&quot;&gt;nest_asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;apply&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  asyncio.set_event_loop(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;.run_until_complete(init())&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This raised an exception: Can&#39;t patch uvloop.Loop.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;uvicorn patches asyncio to use uvloop which is better performant that vanilla asyncio (previous claims were 2x to 4x. In the simple test I ran, even with performance changes in 3.12, asyncio was about 25% slower than uvloop.).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Did some research, but couldn&#39;t find any solution around this other than forcing uvicorn to run with vanilla asyncio&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;div&gt;  uvicorn &lt;span style=&quot;color: #9cdcfe;&quot;&gt;main&lt;/span&gt;:app &lt;span style=&quot;color: #f44747;&quot;&gt;--&lt;/span&gt;loop asyncio&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It didn&#39;t make sense to take a performance hit, just to call a function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I decided to dig deeper into why asyncio.new_event_loop returns uvloop.Loop.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The way uvloop does it is, &lt;a href=&quot;https://github.com/MagicStack/uvloop/blob/master/uvloop/__init__.py#L28&quot; target=&quot;_blank&quot;&gt;it sets the asyncio event_loop_policy&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This gave me an idea, what if we temporarily restore the event loop policy, get a loop, apply nest_asyncio and then restore the event loop policy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div style=&quot;line-height: 18px;&quot;&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;nest_asyncio&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;_cur_event_loop_policy&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;get_event_loop_policy&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;set_event_loop_policy&lt;/span&gt;(&lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;DefaultEventLoopPolicy&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;new_event_loop&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #4ec9b0;&quot;&gt;nest_asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;apply&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;)  &lt;span style=&quot;color: #6a9955;&quot;&gt;# type: ignore&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;set_event_loop&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;result&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;run_until_complete&lt;/span&gt;(init())&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #9cdcfe;&quot;&gt;loop&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;close&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #4ec9b0;&quot;&gt;asyncio&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;set_event_loop_policy&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;_cur_event_loop_policy&lt;/span&gt;)&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This seems to do the trick and I am able to call an async function in my FastAPI application main.py before initializing app.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/2058028562136585249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/2058028562136585249' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2058028562136585249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2058028562136585249'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2024/05/python-calling-async-function-from-sync.html' title='Python - calling async function from a sync code flow'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-7582312790513281543</id><published>2023-06-22T07:14:00.002-07:00</published><updated>2023-06-23T07:06:15.316-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fastapi"/><category scheme="http://www.blogger.com/atom/ns#" term="openapi"/><category scheme="http://www.blogger.com/atom/ns#" term="swagger"/><title type='text'>FastAPI and Swagger2</title><content type='html'>&amp;nbsp;I recently started working on a web project with Python backend.

The hosting was on Google Cloud.&amp;nbsp;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;We built the POC version of the Python backend using the most popular Python3 framework FastAPI. We deployed it on Cloud Run (public) with Docker image and everything worked as expected.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;We then moved on to making the Cloud Run private and adding an API gateway infront of it. 

We saved the http://localhost:8000/openapi.json and ran the gcloud cli to create an API gateway and it failed!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;Looking at the documentation https://cloud.google.com/api-gateway/docs/openapi-overview we realized, Google, for some reason, still only supports OpenAPI 2.0 (Swagger 2.0). Working on AWS for quite some time, I had assumed OpenAPI 3 would be supported.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;We tried figuring out a way to configure FastAPI to generate Swagger 2 spec. But FastAPI only supports OpenAPI 3.x. Many have suggested downloading the openapi.json, passing it through some convertor and then some manual intervention to convert it to Swagger 2.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tiangolo/fastapi/issues/1665&quot;&gt;https://github.com/tiangolo/fastapi/issues/1665&lt;/a&gt; | &lt;a href=&quot;https://github.com/tiangolo/fastapi/discussions/7321&quot;&gt;https://github.com/tiangolo/fastapi/discussions/7321&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/68184751/how-to-generate-swagger-2-0-documentation-for-fastapi&quot;&gt;https://stackoverflow.com/questions/68184751/how-to-generate-swagger-2-0-documentation-for-fastapi&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tiangolo/fastapi/discussions/8235&quot;&gt;https://github.com/tiangolo/fastapi/discussions/8235&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;Since I wanted to use CI/CD, I didn&#39;t want to deal with manual conversion every time developers made some change.

So, I referred the FastAPI OpenAPI related code and came up with &lt;a href=&quot;https://pypi.org/project/fastapi_swagger2&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;Package version&quot; src=&quot;https://img.shields.io/pypi/v/fastapi_swagger2?color=%2334D058&amp;amp;label=fastapi_swagger2&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h2 dir=&quot;auto&quot; style=&quot;border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;Requirements&lt;br /&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;Python 3.8+&lt;br /&gt;FastAPI 0.79.0+&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;h2 dir=&quot;auto&quot; style=&quot;border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;Installation&lt;/h2&gt;&lt;blockquote&gt;&lt;div&gt;&lt;pre style=&quot;border-radius: 6px; box-sizing: border-box; color: #e6edf3; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;$ &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;pip install fastapi_swagger2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Example&lt;/h2&gt;

&lt;blockquote&gt;
    &lt;div class=&quot;highlight highlight-source-python notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: #0d1117; box-sizing: border-box; color: #e6edf3; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, &amp;quot;Noto Sans&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
        &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; color: var(--color-fg-default); font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Union&lt;/span&gt;
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;fastapi&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;FastAPI&lt;/span&gt;
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;fastapi_swagger2&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;FastAPISwagger2&lt;/span&gt;

&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;FastAPI&lt;/span&gt;()
&lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;FastAPISwagger2&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;app&lt;/span&gt;)


&lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;@&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;app&lt;/span&gt;.&lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;/&quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;read_root&lt;/span&gt;():
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;return&lt;/span&gt; {&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;Hello&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;World&quot;&lt;/span&gt;}


&lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;@&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;app&lt;/span&gt;.&lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;/items/{item_id}&quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pl-en&quot; color=&quot;var(--color-prettylights-syntax-entity)&quot; style=&quot;box-sizing: border-box;&quot;&gt;read_item&lt;/span&gt;(&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;item_id&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;q&lt;/span&gt;: &lt;span class=&quot;pl-v&quot; color=&quot;var(--color-prettylights-syntax-variable)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Union&lt;/span&gt;[&lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;str&lt;/span&gt;, &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;None&lt;/span&gt;] &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;None&lt;/span&gt;):
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;return&lt;/span&gt; {&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;item_id&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;item_id&lt;/span&gt;, &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;q&quot;&lt;/span&gt;: &lt;span class=&quot;pl-s1&quot; style=&quot;box-sizing: border-box;&quot;&gt;q&lt;/span&gt;}&lt;/pre&gt;
        &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;br /&gt;This adds following endpoints:&lt;div&gt;&lt;a href=&quot;http://localhost:8000/swagger2.json&quot;&gt;http://localhost:8000/swagger2.json&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://localhost:8000/swagger2/docs&quot;&gt;http://localhost:8000/swagger2/docs&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://localhost:8000/swagger2/redoc&quot;&gt;http://localhost:8000/swagger2/redoc&lt;/a&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/h2&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Generate spec for CI/CD&lt;/h2&gt;&lt;div&gt;&lt;div style=&quot;background-color: #1f1f1f; color: #cccccc; font-family: Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;os&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;yaml&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;app&lt;/span&gt;.&lt;span style=&quot;color: #4ec9b0;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #4fc1ff;&quot;&gt;URL&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;os&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;environ&lt;/span&gt;[&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;CLOUD_RUN_URL&quot;&lt;/span&gt;]&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;servers&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;append&lt;/span&gt;(&lt;span style=&quot;color: #4fc1ff;&quot;&gt;URL&lt;/span&gt;)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;spec&lt;/span&gt; &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;app&lt;/span&gt;.swagger2()&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;spec&lt;/span&gt;[&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;x-google-backend&#39;&lt;/span&gt;] &lt;span style=&quot;color: #d4d4d4;&quot;&gt;=&lt;/span&gt; {&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;address&#39;&lt;/span&gt;: &lt;span style=&quot;color: #4fc1ff;&quot;&gt;URL&lt;/span&gt;}&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;print&lt;/span&gt;(&lt;span style=&quot;color: #4ec9b0;&quot;&gt;yaml&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;dump&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;spec&lt;/span&gt;))&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7582312790513281543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7582312790513281543' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7582312790513281543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7582312790513281543'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2023/06/fastapi-and-swagger2.html' title='FastAPI and Swagger2'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-1470695631077736907</id><published>2021-04-12T08:32:00.005-07:00</published><updated>2021-04-12T09:46:15.060-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gui"/><category scheme="http://www.blogger.com/atom/ns#" term="macos"/><category scheme="http://www.blogger.com/atom/ns#" term="multipass"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><category scheme="http://www.blogger.com/atom/ns#" term="vm"/><category scheme="http://www.blogger.com/atom/ns#" term="xquartz"/><title type='text'>Run GUI applications inside Multipass (Ubuntu) on macOS</title><content type='html'>&lt;p&gt;
  &lt;a href=&quot;https://multipass.run/&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;Multipass&lt;/a&gt; is a nice docker like vm platform from Ubuntu. It can configure the vm with cloud-init so you can prototype your cloud launches locally for free.&amp;nbsp;
&lt;/p&gt;

&lt;p&gt;E.g.
Launch an instance (by default you get the current Ubuntu LTS)
&lt;/p&gt;

&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;&lt;p&gt;$ multipass launch --name foo&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;
You can read more about multipass in the &lt;a href=&quot;https://multipass.run/&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;docs&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Primarly it does seem like just another alternative to docker. But then I found one nice little difference, not a resource hog unlike docker and you don&#39;t run as root.
&lt;/p&gt;
&lt;p&gt;
  Currently to run a GUI application which you just want to try without having to clean up the system, most common approach is create a vm with VirtualBox, VMware Fusion or Parallels. But it can be a time consuming task as it installs everything from scratch.
&lt;/p&gt;

&lt;p&gt;
Getting GUI applications to work on docker is possible &lt;a href=&quot;https://medium.com/@SaravSun/running-gui-applications-inside-docker-containers-83d65c0db110&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;configuration&lt;/a&gt;. But then, atleast on Mac, Docker is a resource hog.
&lt;/p&gt;

&lt;p&gt;
  With multipass I was able to get IntelliJ IDEA with following:
&lt;/p&gt;

&lt;p&gt;
  &lt;u&gt;Prerequisites:&lt;/u&gt;
&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Install &lt;a href=&quot;https://multipass.run/&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;Multipass&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;Install &lt;a href=&quot;https://www.xquartz.org/&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;XQuartz&lt;/a&gt;. Also configure XAuthLocation.
      &lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
echo &quot;XAuthLocation /opt/X11/bin/xauth&quot; &gt;&gt; ~/.ssh/config
      &lt;/blockquote&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

&lt;p&gt;
  Launch a vm with current LTS ubuntu with 4 cores CPU and 4 GB memory
&lt;/p&gt;
&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
  &lt;p&gt;
    $ multipass launch -n idea -c 4 -m 4G
  &lt;/p&gt;
  &lt;p&gt;$ multipass shell idea&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
  &lt;p&gt;$ sudo apt update&lt;/p&gt;
  &lt;p&gt;$ sudo apt install -y libxrender-dev libxtst6 libxi6 fontconfig&lt;/p&gt;
  &lt;p&gt;$ cd /tmp&lt;/p&gt;
  &lt;p&gt;$ curl -L -O https://download.jetbrains.com/idea/ideaIC-2021.1.tar.gz&lt;/p&gt;
  &lt;p&gt;$ sudo tar -xzf ideaIC-2021.1.tar.gz -C /opt&lt;/p&gt;
  &lt;p&gt;$ echo &#39;PATH=/opt/idea-IC-211.6693.111/bin:$PATH&#39; &gt;&gt; ~/.bashrc&lt;/p&gt;
  &lt;p&gt;$ sudo apt install -y openjdk-11-jdk&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You could automate the above with &lt;a href=&quot;https://ubuntu.com/blog/using-cloud-init-with-multipass&quot; target=&quot;_blank&quot; style=&quot;color:#888888&quot;&gt;cloud-init&lt;/a&gt;. (Currently as of this writing multipass only supports yaml configs)&lt;/p&gt;
&lt;p&gt;Now time for the magic part (on the host):&lt;/p&gt;
&lt;p&gt;multipass shell internally is just doing a SSH&lt;/p&gt;
&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
  &lt;p&gt;$ sudo cp &#39;/var/root/Library/Application Support/multipassd/ssh-keys/id_rsa&#39; ~/.ssh/multipass_id_rsa&lt;/p&gt;  
&lt;/blockquote&gt;
&lt;p&gt;Save this script to your PATH&lt;/p&gt;
&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
  &lt;p&gt;$ cat ~/bin/multipass_x_ssh&lt;/p&gt;
  &lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;#!/bin/bash&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;IP=$(multipass info $1 | grep IPv4 | awk &#39;{ print $2 }&#39;)&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;ssh -X -i ~/.ssh/multipass_id_rsa ubuntu@$IP&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now when I want to run idea, all I have to do is:&lt;/p&gt;
&lt;blockquote style=&quot;background-color:#2F2F2F; padding:5px&quot;&gt;
  &lt;p&gt;$ multipass_x_ssh idea&lt;/p&gt;
  &lt;p&gt;$ idea.sh&lt;/p&gt;
&lt;/blockquote&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/1470695631077736907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/1470695631077736907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/1470695631077736907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/1470695631077736907'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2021/04/run-gui-applications-inside-multipass.html' title='Run GUI applications inside Multipass (Ubuntu) on macOS'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-6133158450230475701</id><published>2021-02-27T19:02:00.004-08:00</published><updated>2021-02-27T19:02:46.780-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="big sur"/><category scheme="http://www.blogger.com/atom/ns#" term="implicit"/><category scheme="http://www.blogger.com/atom/ns#" term="macos sendfile"/><category scheme="http://www.blogger.com/atom/ns#" term="pyenv"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>pyenv install error on MacOS Big Sur - sendfile invalid</title><content type='html'>&lt;p&gt;There seems to be some issue going on with pyenv and MacOS Big Sur.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote style=&quot;background-color:#2F2F2F&quot;&gt;&lt;p&gt;./Modules/posixmodule.c:8320:15: error: implicit declaration of function &#39;sendfile&#39; is invalid in C99 [-Werror,-Wimplicit-function-declaration]&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret = sendfile(in, out, offset, &amp;amp;sbytes, &amp;amp;sf, flags);&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;After referring multiple posts, this is what worked for me.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote style=&quot;background-color:#2F2F2F&quot;&gt;&lt;p&gt;brew install zlib bzip2&lt;/p&gt;&lt;p&gt;CFLAGS=&quot;-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include&quot; LDFLAGS=&quot;-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib&quot; pyenv install 3.5.3 --patch &amp;lt; &amp;lt;(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/6133158450230475701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/6133158450230475701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/6133158450230475701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/6133158450230475701'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2021/02/pyenv-install-error-on-macos-big-sur.html' title='pyenv install error on MacOS Big Sur - sendfile invalid'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-7368658990500113766</id><published>2021-02-10T09:52:00.002-08:00</published><updated>2021-02-10T09:52:30.780-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="big sur"/><category scheme="http://www.blogger.com/atom/ns#" term="ethernet"/><category scheme="http://www.blogger.com/atom/ns#" term="macos"/><category scheme="http://www.blogger.com/atom/ns#" term="virtual network"/><category scheme="http://www.blogger.com/atom/ns#" term="vmnet8"/><category scheme="http://www.blogger.com/atom/ns#" term="vmware fusion"/><title type='text'>Vmware Fusion 12 - Mac OS Big Sur - Could not connect Network</title><content type='html'>&lt;p&gt;Was unable to get the network to work after a restart.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;| vmx| I005: VNET: &#39;ethernet0&#39; enable link state propagation, lsp.state = 5&lt;/p&gt;&lt;p&gt;| vmx| I005: DictionaryLoad: Cannot open file &quot;/Library/Preferences/VMware Fusion/config&quot;: No such file or directory.&lt;/p&gt;&lt;p&gt;| vmx| I005: VNET: MACVNetMacosGetRealAdapterType: network type for adapter 0: 8&lt;/p&gt;&lt;p&gt;| vmx| I005: VNET: MACVNetMacosGetVnetProperties: vnet properties: vnet=vmnet8, nat=yes, dhcp=yes (ignored), subnet=172.16.82.0, mask=255.255.255.0, firstAddr=172.16.82.1, lastAddr=172.16.82.127, isIPv6=no, IPv6Prefix=fd15:4ba5:5a2b:1008::, IPv6PrefixLen=64&lt;/p&gt;&lt;p&gt;| vmx| I005: VNET: MACVNetPortVirtApiStartInterface: Waiting on semaphore for adapter: 0&lt;/p&gt;&lt;p&gt;| host-1216256| I005: VNET: MACVNetPortVirtApiStartHandler: starting interface for adapter: 0, status: 1009&lt;/p&gt;&lt;p&gt;| host-1216256| W003: VNET: MACVNetPortVirtApiStartHandler: unable to create virtual intrface for device: 0, status: 1009&lt;/p&gt;&lt;p&gt;| vmx| I005: VNET: Semaphore signalled for adapter: 0, timeoutMs=5000, waitMs=3&lt;/p&gt;&lt;p&gt;| vmx| W003: VNET: MACVNetPortVirtApiStartInterface: Failed to create interface for adapter: 0, handlerStatus: 1009&lt;/p&gt;&lt;p&gt;| vmx| I005: VNET: MACVNetPort_Connect: Ethernet0: can&#39;t start virtual interface&lt;/p&gt;&lt;p&gt;| vmx| I005: Msg_Post: Error&lt;/p&gt;&lt;p&gt;| vmx| I005: [msg.vnet.connectvnet] Could not connect &#39;Ethernet0&#39; to virtual network &#39;/dev/vmnet8&#39;. More information can be found in the vmware.log file.&lt;/p&gt;&lt;p&gt;| vmx| I005: [msg.device.badconnect] Failed to connect virtual device &#39;Ethernet0&#39;.&lt;/p&gt;&lt;p&gt;| vmx| I005: ----------------------------------------&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Here&#39;s what worked for me:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Click on &quot;Apple&quot; logo in menu bar&lt;/li&gt;&lt;li&gt;Click &quot;System Preferences&quot;&lt;/li&gt;&lt;li&gt;Click &quot;Sharing&quot;&lt;/li&gt;&lt;li&gt;Disable &quot;Internet Sharing&quot;&lt;/li&gt;&lt;li&gt;Restart the VM.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7368658990500113766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7368658990500113766' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7368658990500113766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7368658990500113766'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2021/02/vmware-fusion-12-mac-os-big-sur-could.html' title='Vmware Fusion 12 - Mac OS Big Sur - Could not connect Network'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-3674749604068653909</id><published>2020-06-20T17:56:00.000-07:00</published><updated>2020-06-20T17:56:53.711-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="3.8"/><category scheme="http://www.blogger.com/atom/ns#" term="macos"/><category scheme="http://www.blogger.com/atom/ns#" term="pyenv"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="tkinter"/><title type='text'>MacOS pyenv python 3.8 tkinter install</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
brew install pyenv&lt;br /&gt;
&lt;br /&gt;
brew install tcl-tk&lt;br /&gt;
&lt;br /&gt;
echo &#39;export PATH=&quot;$(brew --prefix tcl-tk)/bin:$PATH&quot;&#39; &amp;gt;&amp;gt; ~/.zshrc&lt;br /&gt;
export LDFLAGS=&quot;-L$(brew --prefix tcl-tk)/lib&quot;&lt;br /&gt;
export CPPFLAGS=&quot;-I$(brew --prefix tcl-tk)/include&quot;&lt;br /&gt;
export PKG_CONFIG_PATH=&quot;$(brew --prefix tcl-tk)/lib/pkgconfig&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PYTHON_CONFIGURE_OPTS=&quot;--with-tcltk-includes=&#39;-I$(brew --prefix tcl-tk)/include&#39; --with-tcltk-libs=&#39;-L$(brew --prefix tcl-tk)/lib -ltcl8.6 -ltk8.6&#39;&quot; CFLAGS=&quot;-I$(brew --prefix tcl-tk)/include&quot; pyenv install 3.8.3&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/3674749604068653909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/3674749604068653909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3674749604068653909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3674749604068653909'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2020/06/macos-pyenv-python-38-tkinter-install.html' title='MacOS pyenv python 3.8 tkinter install'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-9157523029922493970</id><published>2018-09-10T00:16:00.002-07:00</published><updated>2018-09-10T10:36:21.021-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="backup"/><category scheme="http://www.blogger.com/atom/ns#" term="duply"/><category scheme="http://www.blogger.com/atom/ns#" term="macos"/><category scheme="http://www.blogger.com/atom/ns#" term="s3"/><title type='text'>Duply backup on MacOS</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Download duplicity from&amp;nbsp;http://duplicity.nongnu.org/&lt;br /&gt;
&lt;br /&gt;
untar&lt;br /&gt;
&lt;br /&gt;
cd&amp;nbsp;duplicity-0.7.18&lt;br /&gt;
&lt;br /&gt;
mkvirtualenv duply_backup&lt;br /&gt;
&lt;br /&gt;
brew install librsync&lt;br /&gt;
brew install gpg&lt;br /&gt;
pip install fasteners&lt;br /&gt;
&lt;br /&gt;
python setup install&lt;br /&gt;
&lt;br /&gt;
Download duply from&amp;nbsp;https://sourceforge.net/projects/ftplicity/files/duply%20%28simple%20duplicity%29/&lt;br /&gt;
&lt;br /&gt;
untar&lt;br /&gt;
&lt;br /&gt;
cd&amp;nbsp;duply_2.1&lt;br /&gt;
&lt;br /&gt;
workon duply_backup&lt;br /&gt;
&lt;br /&gt;
./duply -V&lt;br /&gt;
&amp;nbsp; duply version 2.1&lt;br /&gt;
&amp;nbsp; (http://duply.net)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; Using installed duplicity version 0.7.18, python 2.7.14 (/Users/vkanwade/.virtualenvs/duply_backup/bin/python2), gpg 2.2.10 (Home: /Users/vkanwade/.gnupg), awk &#39;awk version 20070501&#39;, grep &#39;grep (BSD grep) 2.5.1-FreeBSD&#39;, bash &#39;3.2.57(1)-release (x86_64-apple-darwin17)&#39;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
export&amp;nbsp;DUPL_PYTHON_BIN=~/.virtualenvs/duply_backup/bin/python&lt;br /&gt;
export PATH=&quot;$PATH:/opt/duply_2.1/&quot;&lt;br /&gt;
&lt;br /&gt;
duply myprofile create&lt;br /&gt;
vim ~/.duply/myprofile/conf&lt;br /&gt;
&lt;br /&gt;
#GPG_KEY=&#39;_KEY_ID_&#39;&lt;br /&gt;
GPG_PW=&#39;&amp;lt;some random pwd generated with pwgen. store it safe, required for restore&amp;gt;&#39;&lt;br /&gt;
&lt;br /&gt;
TARGET=&#39;s3://&amp;lt; s3_prefix&amp;gt;&amp;lt; s3_region &amp;gt;.amazonaws.com/&amp;lt; s3_bucket &amp;gt;/duply/myprofile&#39;&lt;br /&gt;
# s3_prefix: eu-central-1 &#39;s3.&#39;, else &#39;s3-&#39;&lt;br /&gt;
&lt;br /&gt;
export AWS_ACCESS_KEY_ID=&#39;&amp;lt; aws_s3_backup_id &amp;gt;&#39;&lt;br /&gt;
export AWS_SECRET_ACCESS_KEY=&#39;&amp;lt; aws_s3_backup_secret &amp;gt;&#39;&lt;br /&gt;
DUPL_PARAMS=&quot;$DUPL_PARAMS --allow-source-mismatch --s3-use-new-style --s3-european-buckets &quot;&lt;br /&gt;
&lt;br /&gt;
SOURCE=&#39;/&#39;&lt;br /&gt;
&lt;br /&gt;
MAX_AGE=1M&lt;br /&gt;
&lt;br /&gt;
MAX_FULLBKP_AGE=1M&lt;br /&gt;
DUPL_PARAMS=&quot;$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE &quot;&lt;br /&gt;
&lt;br /&gt;
ARCH_DIR=~/duply-cache&lt;br /&gt;
&lt;br /&gt;
NOTE: just wanted to dump the info. formatting will come.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/9157523029922493970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/9157523029922493970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/9157523029922493970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/9157523029922493970'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2018/09/duply-backup-on-macos.html' title='Duply backup on MacOS'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-7588581396001437237</id><published>2016-10-25T22:21:00.001-07:00</published><updated>2016-10-25T22:25:59.635-07:00</updated><title type='text'>MacOS - Operation not permitted - Can&#39;t upgrade package &#39;six&#39;</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
For most of the packages, python-dateutil is the one which causes all the issue. So just upgrade it an all other installations should be fine.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;background-color: #f3f3f3; color: #000000&quot;&gt;sudo -H pip install --upgrade python-dateutil --ignore-installed six&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7588581396001437237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7588581396001437237' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7588581396001437237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7588581396001437237'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2016/10/macos-operation-not-permitted-cant.html' title='MacOS - Operation not permitted - Can&#39;t upgrade package &#39;six&#39;'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-3332363497792443690</id><published>2016-10-22T23:51:00.000-07:00</published><updated>2016-10-22T23:51:00.244-07:00</updated><title type='text'>&#39;Night Shift&#39; on El Capitan</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;script src=&quot;https://gist.github.com/virajkanwade/ea3431c83b0c84470142216b164135d1.js&quot;&gt;&lt;/script&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/3332363497792443690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/3332363497792443690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3332363497792443690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3332363497792443690'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2016/10/night-shift-on-el-capitan.html' title='&#39;Night Shift&#39; on El Capitan'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-7399591985451197691</id><published>2015-09-22T15:04:00.001-07:00</published><updated>2015-09-22T15:04:43.869-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="file"/><category scheme="http://www.blogger.com/atom/ns#" term="line"/><category scheme="http://www.blogger.com/atom/ns#" term="match"/><category scheme="http://www.blogger.com/atom/ns#" term="output"/><category scheme="http://www.blogger.com/atom/ns#" term="split"/><title type='text'>Bash - Get output after matching line</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ cat file.txt&lt;br /&gt;line 1&lt;br /&gt;line 2&lt;br /&gt;this is the line&lt;br /&gt;line 4&lt;br /&gt;line 5&lt;/blockquote&gt;
&lt;br /&gt;
If you want lines starting from &quot;this is the line&quot;&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ cat file.txt | awk &#39;/this is the line/{ f=1; } f&#39;&lt;br /&gt;this is the line&lt;br /&gt;line 4&lt;br /&gt;line 5&lt;/blockquote&gt;
&lt;br /&gt;
When the line is found, set &lt;i&gt;f&lt;/i&gt; to &lt;i&gt;1&lt;/i&gt;.&lt;br /&gt;
The last &#39;&lt;i&gt;f&lt;/i&gt;&#39; is shortcut to &#39;&lt;i&gt;f == 1 { print }&lt;/i&gt;&#39;&lt;br /&gt;
&lt;br /&gt;
If you want output after the matching line&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ cat file.txt | awk &#39;/this is the line/{ f=1; next; } f&#39;&lt;br /&gt;line 4&lt;br /&gt;line 5&lt;/blockquote&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/7399591985451197691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/7399591985451197691' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7399591985451197691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/7399591985451197691'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2015/09/bash-get-output-after-matching-line.html' title='Bash - Get output after matching line'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-3474759478018342438</id><published>2015-08-01T13:50:00.000-07:00</published><updated>2015-08-01T13:58:05.714-07:00</updated><title type='text'>Get celery init.d scripts</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Downloads init.d scripts (celeryd and celerybeat) for your installed version.&lt;br /&gt;
Also accepts APP_NAME as an argument. Saves the files as celeryd-&amp;lt;app_name&amp;gt; and celerybeat-&amp;lt;app_name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/virajkanwade/a744359c874f8e0a9595.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/3474759478018342438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/3474759478018342438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3474759478018342438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/3474759478018342438'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2015/08/downloads-init.html' title='Get celery init.d scripts'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-145800297225397262</id><published>2015-08-01T13:36:00.000-07:00</published><updated>2015-08-01T13:45:47.322-07:00</updated><title type='text'>Install Redis inside virtualenv</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div&gt;
Just run this script.&lt;br /&gt;
Puts the redis.conf in &lt;i&gt;${VIRTUAL_ENV}/etc/redis.conf&lt;/i&gt;.&lt;br /&gt;
Adds a wrapper &lt;i&gt;redis-server-ve&lt;/i&gt; to use this conf by default.&lt;br /&gt;
&lt;br /&gt;
Defaults to stable release. Else pass the version as an argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;script src=&quot;https://gist.github.com/virajkanwade/0fe8f73651694d82286b.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/145800297225397262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/145800297225397262' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/145800297225397262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/145800297225397262'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2015/08/install-redis-inside-virtualenv.html' title='Install Redis inside virtualenv'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-6088209073211828905</id><published>2014-10-27T16:47:00.000-07:00</published><updated>2014-10-27T16:49:18.372-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="packer"/><category scheme="http://www.blogger.com/atom/ns#" term="qemu-utils"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><category scheme="http://www.blogger.com/atom/ns#" term="VIX"/><category scheme="http://www.blogger.com/atom/ns#" term="vmware player"/><category scheme="http://www.blogger.com/atom/ns#" term="vmware-iso"/><title type='text'>Packer vmware-iso on Ubuntu 14.04 with VMware Player 6</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
VMware build can be done with packer on Ubuntu using VMware Player 6.&lt;br /&gt;
&lt;br /&gt;
Download VMware Player 6 from:&lt;br /&gt;
&lt;a href=&quot;https://my.vmware.com/web/vmware/free#desktop_end_user_computing/vmware_player/6_0|PLAYER-603|product_downloads&quot;&gt;https://my.vmware.com/web/vmware/free#desktop_end_user_computing/vmware_player/6_0|PLAYER-603|product_downloads&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Also, click on Driver &amp;amp; Tools and download the correct version of VIX.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;pre&gt;
$ wget&amp;nbsp;https://download3.vmware.com/software/player/file/VMware-Player-6.0.3-1895310.x86_64.bundle
$ chmod +x VMware-Player-6.0.3-1895310.x86_64.bundle
$ sudo ./VMware-Player-6.0.3-1895310.x86_64.bundle

$ wget https://download3.vmware.com/software/player/file/VMware-VIX-1.13.3-1895310.x86_64.bundle
$ chmod +x VMware-VIX-1.13.3-1895310.x86_64.bundle
$ sudo ./VMware-VIX-1.13.3-1895310.x86_64.bundle

$ sudo apt-get install qemu-utils

$ packer build vmware.json
&lt;/pre&gt;
&lt;br /&gt;
If you see errors like vmware or vmrun not in $PATH, VIX was not installed properly.&lt;br /&gt;
&lt;br /&gt;
If you see errors like &quot;specified version not found&quot;, incorrect version of VIX was installed.&lt;br /&gt;
&lt;br /&gt;
If you see qemu related errors, qemu-utils was not installed.&lt;br /&gt;
&lt;br /&gt;
vmware-iso only outputs the vmware instance as .vmx along with other files.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
To export to ovf/ova format&lt;br /&gt;
&lt;pre&gt;
$ ovftool appliance.vmx appliance.ovf
$ ovftool appliance.vmx appliance.ova
&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/6088209073211828905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/6088209073211828905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/6088209073211828905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/6088209073211828905'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2014/10/packer-vmware-iso-ubuntu-vmware-player.html' title='Packer vmware-iso on Ubuntu 14.04 with VMware Player 6'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-4305986418593975198</id><published>2013-07-18T11:08:00.001-07:00</published><updated>2013-11-20T13:49:55.793-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="501"/><category scheme="http://www.blogger.com/atom/ns#" term="dialout"/><category scheme="http://www.blogger.com/atom/ns#" term="folders"/><category scheme="http://www.blogger.com/atom/ns#" term="guest"/><category scheme="http://www.blogger.com/atom/ns#" term="host"/><category scheme="http://www.blogger.com/atom/ns#" term="permissions"/><category scheme="http://www.blogger.com/atom/ns#" term="shared"/><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu"/><category scheme="http://www.blogger.com/atom/ns#" term="vmware fusion"/><title type='text'>VMware Fusion - Permissions on Shared Folders on Ubuntu</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
VMware Fusion provides a nice functionality of sharing folder from host (Mac OSX) to guest (Ubuntu). But then, it seems they are more focused on windows guests, because they screwup on file permissions of shared folders.&lt;br /&gt;
&lt;br /&gt;
&quot;ls -al /mnt/hgfs&quot; will show 501 dialout as user and group, which is sure to cause permission issues on linux guest.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update: Found a more persistent alternative&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;1.&lt;/b&gt;&amp;nbsp;&lt;i&gt;sudo vim /etc/vmware-tools/services.sh&lt;/i&gt;&lt;br /&gt;
&lt;b&gt;2.&lt;/b&gt; Search for &#39;&lt;i&gt;vmhgfs_mnt=&quot;/mnt/hgfs&quot;&lt;/i&gt;&#39;. After this line add: &#39;&lt;u&gt;vmuser=${VMWARE_MNT_USER:-root}&lt;/u&gt;&#39;&lt;br /&gt;
&lt;b&gt;3.&lt;/b&gt; Then search for &#39;&lt;i&gt;vmware_exec_selinux &quot;mount -t vmhgfs .host:/ $vmhgfs_mnt&quot;&lt;/i&gt;&#39; and replace it with following section:&lt;br /&gt;
&lt;u style=&quot;background-color: #351c75;&quot;&gt;&amp;nbsp; &amp;nbsp;uid=`id --user $vmuser`&lt;/u&gt;&lt;br /&gt;
&lt;u style=&quot;background-color: #351c75;&quot;&gt;&amp;nbsp; &amp;nbsp;gid=`id --group $vmuser`&lt;/u&gt;&lt;br /&gt;
&lt;u style=&quot;background-color: #351c75;&quot;&gt;&amp;nbsp; &amp;nbsp;vmware_exec_selinux &quot;mount -t vmhgfs .host:/ $vmhgfs_mnt -o uid=$uid,gid=$gid&quot;&lt;/u&gt;&lt;br /&gt;
&lt;b&gt;4.&lt;/b&gt;&amp;nbsp;&lt;i&gt;sudo vim /etc/init/vmware-tools.conf&lt;/i&gt;&lt;br /&gt;
Before the &quot;pre-start&quot; and &quot;post-stop&quot; lines add:&lt;br /&gt;
&lt;u&gt;env VMWARE_MNT_USER=[The guest user you want]&lt;the be=&quot;&quot; guest=&quot;&quot; on=&quot;&quot; present=&quot;&quot; should=&quot;&quot; user=&quot;&quot; want.=&quot;&quot; you=&quot;&quot;&gt;&lt;/the&gt;&lt;/u&gt;&lt;br /&gt;
&lt;b&gt;5.&lt;/b&gt; &lt;i&gt;sudo reboot&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;NOTE:&lt;/b&gt; This will have to be redone when you update/ reinstall vmware-tools&lt;br /&gt;
&lt;br /&gt;
&lt;strike&gt;To fix this:&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;ssh to your ubuntu.&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;run command &quot;id&quot;. Make note of uid and gid.&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;&quot;sudo vim /etc/mtab&quot;&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;look for line &quot;.host:/ /mnt/hgfs vmhgfs rw,ttl=1 0 0&quot;&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;Duplicate the line and change it to &quot;.host:/ /mnt/hgfs vmhgfs rw,ttl=1,uid=1000,gid=1000 0 0&quot;&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;&quot;sudo umount /mnt/hgfs&quot;&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;&quot;sudo mount /mnt/hgfs&quot;&lt;/strike&gt;&lt;br /&gt;
&lt;br /&gt;
Now do a &quot;ls -al /mnt/hgfs&quot; to verify if correct username and group are shown.&lt;br /&gt;
&lt;br /&gt;
Ideally, vmware fusion should be making this as transparent as possible. But then again, they don&#39;t care because they still don&#39;t have a real competition. Once, we do some real competitors, maybe then might start worrying about such minor but key items.&lt;br /&gt;
&lt;br /&gt;
&lt;strike&gt;Currently, I spend more time trying to get it working than actually working on a VM. I am desperately looking for a better alternative.&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;
This seems like a pretty neat fix. On the sharing screen, VMWare could add a simple textbox for user name and next time vmware tools are installed, use this value while generating the vmware-tools.conf file.&lt;br /&gt;
&lt;br /&gt;
Not sure when VMWare will take note of such minor issues.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/4305986418593975198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/4305986418593975198' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/4305986418593975198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/4305986418593975198'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2013/07/vmware-fusion-permissions-on-shared.html' title='VMware Fusion - Permissions on Shared Folders on Ubuntu'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-5118271391931498522</id><published>2013-05-07T19:38:00.000-07:00</published><updated>2013-05-07T21:38:10.041-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="--with-pylons"/><category scheme="http://www.blogger.com/atom/ns#" term="nose"/><category scheme="http://www.blogger.com/atom/ns#" term="nosetests"/><category scheme="http://www.blogger.com/atom/ns#" term="pylons"/><category scheme="http://www.blogger.com/atom/ns#" term="pylons 1.0"/><category scheme="http://www.blogger.com/atom/ns#" term="pylons 1.0.1"/><category scheme="http://www.blogger.com/atom/ns#" term="setup.cfg"/><category scheme="http://www.blogger.com/atom/ns#" term="with_pylons"/><title type='text'>error in setup.cfg: command &#39;nosetests&#39; has no such option &#39;with_pylons&#39;</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
When running nosetests, if you see error in setup.cfg: command &#39;nosetests&#39; has no such option &#39;with_pylons&#39; or Error reading config file &#39;setup.cfg&#39;: no such option &#39;with-pylons&#39;, it could be because you have Pylons==1.0* installed. Pylons==1.0* does not register itself as a nose plugin (https://github.com/Pylons/pylons/issues/13). Use following work arounds: &lt;br /&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;b&gt;For &quot;python setup.py nosetests&quot;:&lt;/b&gt;&lt;br /&gt;
Add the following to your projects &quot;setup.py -&gt; entry_points&quot;  and &quot;&lt;project&gt;.egg-info/entry_points.txt&quot;
&lt;pre&gt;
    [nose.plugins]
    pylons = pylons.test:PylonsPlugin
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;For &quot;nosetests --version&quot;:&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;
sudo vim `which nosetests`
&lt;/pre&gt;
Make it look something like:
&lt;pre&gt;
#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: &#39;nose==1.3.0&#39;,&#39;console_scripts&#39;,&#39;nosetests&#39;
__requires__ = &#39;nose==1.3.0&#39;
import sys
from pkg_resources import load_entry_point

addplugins = []

try:
    import pylons
    if pylons.__version__[0] == &#39;1&#39;:
        from pylons.test import PylonsPlugin
        addplugins.append(PylonsPlugin())
except ImportError:
    pass

if __name__ == &#39;__main__&#39;:
    sys.exit(
        load_entry_point(&#39;nose==1.3.0&#39;, &#39;console_scripts&#39;, &#39;nosetests&#39;)(addplugins=addplugins)
    )
&lt;/pre&gt;
now you should be able to run it as &lt;b&gt;nosetests --version&lt;/b&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/5118271391931498522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/5118271391931498522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/5118271391931498522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/5118271391931498522'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2013/05/error-in-setupcfg-command-nosetests-has.html' title='error in setup.cfg: command &#39;nosetests&#39; has no such option &#39;with_pylons&#39;'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-8907789633550355937</id><published>2013-04-19T11:16:00.001-07:00</published><updated>2013-04-19T11:16:34.449-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="multiple python"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="virtualenv"/><category scheme="http://www.blogger.com/atom/ns#" term="virtualenvwrapper"/><category scheme="http://www.blogger.com/atom/ns#" term="yolk"/><title type='text'>Working with multiple Python projects</title><content type='html'>&lt;div&gt;While working with multiple Python projects, you might soon realize you need different versions of the same Py package or packages are conflicting between multiple projects.&lt;/div&gt;

&lt;div&gt;&lt;a href=&quot;http://www.virtualenv.org/&quot; target=&quot;_blank&quot;&gt;VirtualEnv&lt;/a&gt; to your rescue.&lt;/div&gt;

&lt;div&gt;
But once you go through the docs, install and start using virtualenv, you might soon realize it is a little cumbersome.
&lt;ol&gt;
&lt;li&gt;You need to provide the complete path where you want to save your virtualenv environment folder. &lt;span&gt;virtualenv proj1&lt;/span&gt; will just create the env in your current directory. If you are using a long path to store your envs, it might be a pain to put it in every-time.&lt;/li&gt;
&lt;li&gt;To activate an env, &lt;span&gt;source &amp;lt;path-to-envs&amp;gt;/proj1/bin/activate&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;To find all envs, you have to &lt;span&gt;ls &amp;lt;path-to-envs&amp;gt;&lt;/span&gt;. But this works only if you have all yours envs in a single place.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;div&gt;Don&#39;t worry, &lt;a href=&quot;http://virtualenvwrapper.readthedocs.org/&quot; target=&quot;_blank&quot;&gt;VirtualEnvWrapper&lt;/a&gt; is here to help you.&lt;/div&gt;

&lt;div&gt;Now you have a wrapper which provides you some shortcuts to the virtualenv commands. But it doesn&#39;t end there. VirtualEnvWrapper provides you with the an extension system.&lt;/div&gt;

&lt;div&gt;&lt;span&gt;ls $WORKON_HOME&lt;/span&gt; and you will find files starting with &quot;post&quot; and &quot;pre&quot;. These are simple shell scripts. You can add your commands to these scripts and they will be everytime you run one of the commands.&lt;/div&gt;

&lt;div&gt;It doesn&#39;t end there. You can also have separate extensions for each of your env. &lt;span&gt;ls $WORKON_HOME/proj1/bin/&lt;/span&gt; should show some similar files starting with &quot;post&quot; and &quot;pre&quot;. For eg. To go to your source folder when you activate your env, just add &quot;cd &lt;path&gt; to &quot;postactivate&quot;&lt;/div&gt;

&lt;div&gt;All said and done, one thing that might trouble you is figure out what packages are available in your current env?&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;https://pypi.python.org/pypi/yolk&quot; target=&quot;_blank&quot;&gt;Yolk&lt;/a&gt; will prove useful here. Remember, you can write extensions in wrapper. Just add &lt;span&gt;pip install yolk&lt;/span&gt; to &quot;$WORKON_HOME/postmkvirtualenv&quot; and yolk will be installed on all new virtual envs created automatically. You can then activate your env and just use &lt;span&gt;yolk -l&lt;/span&gt; to list packages available in that env.&lt;/div&gt;

&lt;span style=&quot;font-style: italics; color: red;&quot;&gt;Not much time for formatting. Will do it later.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/8907789633550355937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/8907789633550355937' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8907789633550355937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/8907789633550355937'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2013/04/working-with-multiple-python-projects.html' title='Working with multiple Python projects'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-2151384764801588411</id><published>2013-04-03T01:10:00.000-07:00</published><updated>2013-04-03T01:10:51.436-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="4.2.2"/><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="ATT"/><category scheme="http://www.blogger.com/atom/ns#" term="CyanogenMod 10.1"/><category scheme="http://www.blogger.com/atom/ns#" term="JellyBean"/><category scheme="http://www.blogger.com/atom/ns#" term="Samsung"/><category scheme="http://www.blogger.com/atom/ns#" term="Skyrocket"/><category scheme="http://www.blogger.com/atom/ns#" term="TWRP"/><title type='text'>Install CyanogenMod 10.1 (JellyBean Android 4.2.2) on Samsung S2 Skyrocket</title><content type='html'>&lt;style&gt;

&lt;/style&gt;

&lt;p&gt;&lt;span style=&quot;color:red&quot;&gt;Before you begin:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You NEED a windows machine (atleast as of now) for odin.&lt;/li&gt;
&lt;li&gt;Download using Chrome/ Firefox to avoid issues with tar/ md5 downloads.&lt;/li&gt;
&lt;li&gt;Read all steps before you start anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;&lt;i&gt;&lt;u&gt;5 simple steps:&lt;/u&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Download CyanogenMod 10.1 and gapps, copy it on the internal external SD card&lt;/li&gt;
  &lt;li&gt;Download and run odin on Windows machine&lt;/li&gt;
  &lt;li&gt;Download and install TWRP using Odin&lt;/li&gt;
  &lt;li&gt;Boot in recovery and install the ROM using TWRP&lt;/li&gt;
  &lt;li&gt;Install gapps using TWRP&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b&gt;&lt;i&gt;&lt;u&gt;Lets get going:&lt;/u&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;CyanogenMod 10.1:&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Go to &lt;a href=&quot;http://get.cm/?device=skyrocket&quot;&gt;http://get.cm/?device=skyrocket&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;
        Select the type of  build
        &lt;ul&gt;
          &lt;li&gt;&lt;b&gt;Stable&lt;/b&gt; - Stable. Well tested. But will not have latest features.&lt;/li&gt;
          &lt;li&gt;&lt;b&gt;Nightly&lt;/b&gt; - Nightly builds. Latest features added but unstable.&lt;/li&gt;
          &lt;li&gt;&lt;b&gt;M snapshot (Experimental)&lt;/b&gt; - Similar to nightly. You could call them monthly builds. Somewhere between stable and nightly.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Copy the file onto the phone using USB transfer.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;GApps&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Go to &lt;a href=&quot;http://goo.im/gapps&quot;&gt;http://goo.im/gapps&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Download the gapps which match your CyanogenMod version.&lt;/li&gt;
      &lt;li&gt;Copy the file onto the phone using USB transfer.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;TWRP (Similar to clockworkmod [CWM])&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Download TWRP from &lt;a href=&quot;http://d-h.st/Xo2&quot;&gt;http://d-h.st/Xo2&lt;/a&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;Odin&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Download odin from &lt;a href=&quot;http://forum.xda-developers.com/attachment.php?attachmentid=925569&amp;amp;d=1330549534&quot;&gt;http://forum.xda-developers.com/attachment.php?attachmentid=925569&amp;amp;d=1330549534&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Extract the zip.&lt;/li&gt;
      &lt;li&gt;Run the exe.&lt;/li&gt;
      &lt;li&gt;Check &quot;auto-boot&quot;. Uncheck all other options&lt;/li&gt;
      &lt;li&gt;Click on &quot;PDA&quot; button. Select TWRP tar file.&lt;/li&gt;
      &lt;li&gt;HOLD YOUR HORSES HERE&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;Process - Install TWRP&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Put the phone into download mode. (Download mode is different from recovery mode.)&lt;/li&gt;
      &lt;li&gt;Connect USB cable to computer but not the phone.&lt;/li&gt;
      &lt;li&gt;Shutdown and remove the battery of the phone&lt;/li&gt;
      &lt;li&gt;Wait for sometime and reinsert the battery.&lt;/li&gt;
      &lt;li&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;AT&amp;amp;T&lt;/b&gt; - Hold both volume buttons.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Rogers&lt;/b&gt; - Hold only volume down button.&lt;/li&gt;&lt;/ul&gt;(Do not release the buttons until instructed to do so. Do not touch the power button.)&lt;/li&gt;
      &lt;li&gt;Insert the usb cable into the phone. The phone will boot up. When you see a download mode page with a little yellow triangle at bottom, release the volume button(s).&lt;/li&gt;
      &lt;li&gt;Now press the volume up button as per the instructions on the screen to continue to download mode.&lt;/li&gt;
      &lt;li&gt;Odin should have recognized your phone now. You should see a green box with com port listed.&lt;/li&gt;
      &lt;li&gt;Click start in Odin.&lt;/li&gt;
      &lt;li&gt;When odin is finished flashing, you should see a green box with Pass written right above the com port green box.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;b&gt;&lt;u&gt;Process - Install CyanogenMod 10.1&lt;/u&gt;&lt;/b&gt;
    &lt;ol&gt;
      &lt;li&gt;Put the phone in recovery mode:&lt;/li&gt;
      &lt;li&gt;Turn off phone and unplug USB.&lt;/li&gt;
      &lt;li&gt;Hold down both volume keys.&lt;/li&gt;
      &lt;li&gt;Hold power button till you feel the phone vibrate. (Release only power button, not the volume keys when the phone vibrates.)&lt;/li&gt;
      &lt;li&gt;When the screen goes black, release volume keys.&lt;/li&gt;
      &lt;li&gt;You should now be in recovery mode.&lt;/li&gt;
      &lt;li&gt;It is a good idea to backup here.&lt;/li&gt;
      &lt;li&gt;Click on install button.&lt;/li&gt;
      &lt;li&gt;Select the cyanogenmod zip file from internal/ external sd card and follow on screen instructions to complete the install.&lt;/li&gt;
      &lt;li&gt;Click Home.&lt;/li&gt;
      &lt;li&gt;Click Wipe.&lt;/li&gt;
      &lt;li&gt;Click on Cache, Dalvik Cache and Factory Reset.&lt;/li&gt;
      &lt;li&gt;Click on back button.&lt;/li&gt;
      &lt;li&gt;Click on Reboot -&amp;gt; System.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we reset cache, the first boot could take 5-10 mins. But if it is taking longer, go to recovery mode and try other options in Wipe menu of TWRP. Then reboot.&lt;/p&gt;
&lt;p&gt;On first boot, you might panic to see none of the Google related apps available. Not even Google Play. Thats where the gapps we downloaded come into picture.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;&lt;u&gt;Install GApps&lt;/u&gt;&lt;/b&gt;
  &lt;ol&gt;
  &lt;li&gt;Go to recovery mode.&lt;/li&gt;
  &lt;li&gt;Click Install and select the gapps file. Complete the install.&lt;/li&gt;
  &lt;li&gt;Reboot.&lt;/li&gt;
  &lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should be good to go.&lt;/p&gt;

&lt;p&gt;References&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://forum.xda-developers.com/showthread.php?t=1773659&quot;&gt;http://forum.xda-developers.com/showthread.php?t=1773659&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;span style=&quot;color:red&quot;&gt;&lt;b&gt;&lt;i&gt;Need some more time to work on the post formatting. But instructions are pretty much covered.&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/2151384764801588411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/2151384764801588411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2151384764801588411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2151384764801588411'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2013/04/install-cyanogenmod-101-jellybean.html' title='Install CyanogenMod 10.1 (JellyBean Android 4.2.2) on Samsung S2 Skyrocket'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14111654.post-2468795395891581416</id><published>2012-12-25T07:30:00.000-08:00</published><updated>2012-12-25T07:30:35.094-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="google-docs-api"/><category scheme="http://www.blogger.com/atom/ns#" term="google-drive-sdk"/><title type='text'>MimeTypes for Google Docs and Drive</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;pre&gt;
Google Docs: &lt;span style=&quot;color: #33ffff; font-size: 10px;&quot;&gt;application/vnd.google-apps.document&lt;/span&gt;
Google Presentations: &lt;span style=&quot;color: #33ffff; font-size: 10px;&quot;&gt;application/vnd.google-apps.presentation&lt;/span&gt;
Google Spreadsheets: &lt;span style=&quot;color: #33ffff; font-size: 10px;&quot;&gt;application/vnd.google-apps.spreadsheet&lt;/span&gt;
Google Drawing: &lt;span style=&quot;color: #33ffff; font-size: 10px;&quot;&gt;application/vnd.google-apps.drawing&lt;/span&gt;

Few more of Google Docs and Google Drive MIME types:
&lt;span style=&quot;color: #33ffff; font-size: 10px;&quot;&gt;application/vnd.google-apps.audio
application/vnd.google-apps.document
application/vnd.google-apps.drawing
application/vnd.google-apps.file
application/vnd.google-apps.folder
application/vnd.google-apps.form
application/vnd.google-apps.fusiontable
application/vnd.google-apps.kix
application/vnd.google-apps.photo
application/vnd.google-apps.presentation
application/vnd.google-apps.script
application/vnd.google-apps.sites
application/vnd.google-apps.spreadsheet
application/vnd.google-apps.unknown
application/vnd.google-apps.video
&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://viraj-workstuff.blogspot.com/feeds/2468795395891581416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14111654/2468795395891581416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2468795395891581416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14111654/posts/default/2468795395891581416'/><link rel='alternate' type='text/html' href='http://viraj-workstuff.blogspot.com/2012/12/mimetypes-for-google-docs-and-drive.html' title='MimeTypes for Google Docs and Drive'/><author><name>V&#39;Raj Kanwade</name><uri>http://www.blogger.com/profile/02009354206906624155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>